One of the core tasks of [fleXive] is to store and query data. Like in relational databases or well-formed XML files, data needs to match a predefined structure. When [fleXive] was designed the requirements were as follows:
A good analogy to explain how structures in [fleXive] are organised are classes and object instances: a
class in
an object oriented programming language describes which attributes (in [fleXive] called
properties) are available.
If an attribute itself acts like a container for other attributes we call it a
group.
We call the class analogon
Type
(implemented in the class
FxType
), attributes
property
(implemented in
FxProperty
) and a collection of attributes
Group
(implemented in
FxGroup
).
To enable reuse of properties and groups these entities are independent of types and need to be assigned to types (and respectively groups). The benefit of this system - although it might sound a bit confusing at first glance - is that different types and assignments can share the same property which can be a big advantage for query operations [1] .
A special extension to types are relations (implemented in
FxType
, mode:
Relation
) which mimics the behaviour of attributed n:m relations known from SQL.
Structure elements can be addressed using XPath-like expressions as shown in the section called “Content Engine”.
Element | Class | Description |
---|---|---|
Type |
FxType
|
A type, identified by its name, defines behaviour (what kind of permissions may be applied, storage model or language mode is to be used, etc.) and structure (properties and groups are assigned to types). |
Relation |
FxType
(mode:Relation )
|
A relation is basically a type that relates (or links) two other types together. A good analogy is an attributed relation known from SQL. It is possible to define how many times a specific instance may be used as a relation source or destination and which types may be related. |
Property |
FxProperty
|
A property defines a name and a datatype (and some options). Thats all there is to it! It can only exist (and is of relevance) if it is assigned to a type or group. The purpose of keeping properties and their assignments separate is the ability to share them and query across multiple types with a single property. |
Group |
FxGroup
|
A group serves as a container for properties and combines them to an entity. Groups - just
like properties can not exist without assignments to types (
FxGroupAssignment ). The purpose for their existance is like for properties: the
ability to share and query across multiple types.
|
Assignment |
FxAssignment
|
An assignment is the correlation of groups and properties to types. A group or property can only be used in instances if it is connected to a group assignment or a type. |
Property assignment |
FxPropertyAssignment
|
The assignment of a property to a group assignment or a type. If the property that is being assigned permits, settings like the access control list or options may be overridden. |
Group assignment |
FxGroupAssignment
|
The assignment of a group to a group assignment or a type. If the group that is being assigned permits, settings like the access control list or options may be overridden. |
Following the convention on how to update or create new instances of classes in [fleXive], for every class
exists (or should exist ;-) ) an editable class. These editable classes can either be instantiated with
ClassName.createNew(..)
or
classInstance.asEditable()
depending on if you want to create a new instance or edit an existing.
A type, identified by its name, defines behaviour (what kind of permissions may be applied, storage model or language mode is to be used, etc.) and structure (properties and groups are assigned to types).
A system internal and somewhat special type is the "Root" type: It serves as a virtual repository to which groups or properties can be assigned, which in turn can be reused in other types or assignments without the need of inheritance.
The following is a list of parameters that can be passed as arguments to
FxTypeEdit
when editing or creating a new type:
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
ACL |
setACL(ACL acl)
|
X | X | The ACL which is checked when new instances of this type are created. Will only be checked if the type is configured to check permissions. |
Default instance ACL |
setDefaultInstanceACL(ACL defaultInstanceACL)
|
X | X | Sets the default instance ACL which is assigned to newly created content instances of that type per default. |
Category |
setCategory(TypeCategory category)
|
X | X | A type can be assigned the categories
User
orSystem. A User categorized type can be edited by anyone with
proper roles (StructureManagement ), whereas System categorized types are
ment to be [fleXive] internal and only to be changed by users with the role
GlobalSupervisor . The mode may only be changed by users with the role
GlobalSupervisor
(under ordinary circumstances changing the category of a type should never be
necessary).
|
Check validity |
setCheckValidity(boolean checkValidity)
|
X | X | If set totrue , content instances can be assigned a
validFrom
and
validUntil
Date.
FxContent
instances provide anisValid(long time) -Method to check if they
are valid at the requested time. This feature is particularly useful in queries since
only valid content instances will be returned. Using this feature allows for instance
time triggered publication (and removal) of articles.
|
Label |
setLabel(String label)
|
X | X | Set a label for the type. Of relevance only to user interfaces. |
Enable parent assignments |
setEnableParentAssignments(boolean enableParentAssignments)
|
X | - | If a type is derived from another type, this flag decides if the derived assignments
should be enabled. This is by default enabled when creating a derived type:
FxTypeEdit.createNew(String name, FxString label, ACL acl, FxType parent)
and can be disabled using this method before the derived type is saved.
|
History age |
setHistoryAge(long historyAge)
|
X | X | If
trackHistory
is enabled for this type, the
historyAge
determines the duration for which history entries exist. All entries older than
this time (in milliseconds) will be removed. History entries are changes to the type or
instances and are not fully implemented yet.
|
Language mode |
setLanguage(LanguageMode language)
|
X | (X) | Set one of the supported language modes:
|
Maximum destination count (Relation) |
setMaxRelDestination(int maxRelDestination)
|
(X) | (X) | Restrict the total number of instances that may be related to a source instance using
this relation type. The value
0
means unlimited. This value can only be set if the type is a relation and no instances
would invalidate this restriction.
|
Maximum source count (Relation) |
setMaxRelSource(int maxRelSource)
|
(X) | (X) | Restrict the total number of instances that may be related to a destination instance
using
this relation type. The value
0
means unlimited. This value can only be set if the type is a relation and no instances
would invalidate this restriction.
|
Maximum versions |
setMaxVersions(long maxVersions)
|
X | X | Set the max. number of instance versions to keep, if negative unlimited,
0
does not keep any versions.
|
Mode |
setMode(TypeMode mode)
|
X | (X) | Set if this type is to be used as a regular type or as a relation. Changing the mode is
currently only allowed if no content instance exist.
Possible modes are:
|
Name |
setName(String name)
|
X | X | The name of the type. Has to be unique. |
Permissions |
setPermissions(byte permissions)
|
X | X | Set the permissions to check. The parameter contains the bitcoded types of permissions
that
should be checked. Please use the
setUseXXXPermission() -convenience methods, where XXX is Type,
Property, Step or Instance. If you want to use bit coded permissions, use these
constants:
|
Remove instances with relation types |
setRemoveInstancesWithRelationTypes(boolean
removeInstancesWithRelationTypes)
|
- | (X) | Only applies to relations: If relation entries are removed (for instance,
you no longer want to relate Type A and B using this relation), all instances of
this relation type that relate the removed
FxTypeRelation will also be removed.
|
State |
setState(TypeState state)
|
X | X | Changing the state allows to (de-)activate a type.
|
Track history |
setTrackHistory(boolean trackHistory)
|
X | X | Enables history tracking (will log changes to the type itself or instances). How long
history entries are kept can be set with
setHistoryAge(long)
|
Use instance permissions |
setUseInstancePermissions(boolean use)
|
X | X | Should instance permissions be checked? If enabled, the ACL assigned to instances will be checked. |
Use property permissions |
setUsePropertyPermissions(boolean use)
|
X | X | Should property (assignment) permissions be checked? If enabled, the ACL assigned to property assignments will be checked. Property permission checks are disabled by default and should only be used if really necessary (i.e. if you want to hide specific company or department internal properties from users that under normal circumstances should be allowed to read the instance). |
Use step permissions |
setUseStepPermissions(boolean use)
|
X | X | Should step permissions be checked? If enabled, the ACL assigned to workflow steps will be checked. Enable these checks if you want to prevent users from seeing/using instances in certain steps (i.e. an editor should not be allowed to edit already published articles - this is something only users from the quality assurance department should be allowed to do). |
Use type permissions |
setUseTypePermissions(boolean use)
|
X | X | Should type permissions be checked? If enabled, the ACL assigned to this type will be checked. Disabling this check, will allow everyone to create or remove instances of this type (if instance permission checks are enabled, they will of course still be checked in the case of a removal). |
Allow multiple instance ACLs |
setMultipleContentACLs(boolean value)
|
X | X | If true, multiple content instance ACLs are allowed for content instances of this type. |
Workflow |
setWorkflow(Workflow workflow)
|
X | (X) | Assign a workflow to this type. For existing types the workflow can only be changed if no instances exist. |
In the following example we create a new type "Customer", provide a multilingual label and assign an access control list:
Example 6.4. Creating a new FxType
FxTypeEdit.createNew("Customer") // .setLabel( // new FxString(FxLanguage.ENGLISH, "A generic customer") .setTranslation(FxLanguage.GERMAN, "Ein generischer Kunde")) .setACL(CacheAdmin.getEnvironment().getACL(ACLCategory.STRUCTURE.getDefaultId())) // .save(); // FxType typeByName = CacheAdmin.getEnvironment().getType("Customer"); //
Create a new editable FxType instance with the type name "Customer". The type name is unique for the entire division and can be used to lookup the type afterwards. | |
The multilingual type label is initialized with an English and German type label. | |
Assign an ACL that is used for all instances of that type. Note that you can skip this step if you want to use the default structure ACL (like in this example). | |
The type is created in the database. You can add properties to the type as shown in Example 6.13, “Creating a "Person" type in Java”. | |
This line just serves as an example how to retrieve the a reference to the new type. Saving the instance automatically forced a reload of the cached environment, that why we can retrieve it from the cache here. |
Another way to create a new type would be to use the
GroovyTypeBuilder
:
Example 6.5. Creating a new FxType using the GroovyTypeBuilder
import com.flexive.shared.scripting.groovy.* import com.flexive.shared.value.* import com.flexive.shared.security.* import com.flexive.shared.* def typeDesc = new FxString("A generic customer") typeDesc.setTranslation(FxLanguage.GERMAN, "Ein generischer Kunde") new GroovyTypeBuilder().customer(description: typeDesc, acl: CacheAdmin.environment.getACL(ACLCategory.STRUCTURE.defaultId)) { } def type = CacheAdmin.environment.getType("Customer") return type.name
If executed in the Groovy-Console the code above would return CUSTOMER.
Every data type can potentially support values for different languages - depending on the properties' and property assignments' multilingual support settings.
Data type | FxValue class | Description |
---|---|---|
HTML |
FxHTML
|
HTML markup. Unlimited in length. Offers the ability to use HTML editors in user interfaces. |
String1024 |
FxString
|
A String with a maximum length of 1024 characters. Use this data type in favor of
Text
if you don't need more than 1024 characters, since usually
Text
is stored in
CLOB
Database columns while
String1024
uses
VARCHAR
columns.
|
Text |
FxString
|
Like
String1024
but unlimited in length.
|
Number |
FxNumber
|
Numerical type corresponding to the Java
Integer
class.
|
LargeNumber |
FxLargeNumber
|
Numerical type corresponding to the Java
Long
class.
|
Float |
FxFloat
|
Numerical type corresponding to the Java
Float
class.
|
Double |
FxDouble
|
Numerical type corresponding to the Java
Double
class.
|
Date |
FxDate
|
A date corresponding to the Java
Date
class. Note that there is no time information saved!
|
DateTime |
FxDate
|
A date corresponding to the Java
Date
class. This data type stores date and time information.
|
DateRange |
FxDateRange
|
A date range corresponding to two Java
Date
class instances with a start- and enddate.
Note that there is no time information saved!
|
DateTimeRange |
FxDateTimeRange
|
A date range corresponding to two Java
Date
class instances with a start- and enddate.
Time information is saved as well using this data type.
|
Boolean |
FxBoolean
|
A boolean value corresponding to the Java
Boolean
class.
|
Binary |
FxBinary
|
This data type stores information about a binary content and allows streaming of that content. For more information please refer to the section called “Handling binary content” |
Reference |
FxReference
|
A reference to a content instance, identified by its primary key
(FxPK ).
|
InlineReference |
-
|
This data type is only planned but not implemented. It will allow to create contents that do not exist on their own (and can not be loaded on their own or queried for) but embedded in another content instance. Their XPath addressing will be relative to their parent group in the embedding content. |
SelectOne |
FxSelectOne
|
This data type allows the selection of one entry of a SelectList. See the section called “Select lists” for further information about select lists. |
SelectMany |
FxSelectMany
|
This data type allows the selection of many entries of a SelectList. See the section called “Select lists” for further information about select lists. |
Working with binary content is like working with ordinary input- and outputstreams in Java. For uploading a
binary an
InputStream
and for downloading an
OutputStream
has to be passed. Transfer of binaries is handled by [fleXive]'s own streaming
framework fxStream. It uses nonblocking tcp sockets as transport medium if the client and server part
exist in different virtual machines and is able to detect if they run within the same VM for optimal
performance.
Example 6.6. Handling binary content
File testFile = new File("src/framework/testresources/image/Exif.JPG"); FxType type = CacheAdmin.getEnvironment().getType(IMAGE_TYPE); FileInputStream fis = new FileInputStream(testFile); BinaryDescriptor binary = new BinaryDescriptor(testFile.getName(), testFile.length(), fis); // FxContent img = co.initialize(type.getId()); img.setValue("/File", new FxBinary(false, binary)); // img.setValue("/Filename", new FxString(false, "Exif.JPG")); FxPK pk = co.save(img); FxContent loaded = co.load(pk); FxBinary bin = (FxBinary)loaded.getValue("/File"); File comp = File.createTempFile("Exif","JPG"); FileOutputStream fos = new FileOutputStream(comp); bin.getBestTranslation().download(fos); // fos.close();This example shows how easy it is to upload a binary programatically to the
ContentEngine
and download it from the saved instance.
A
| |
Simply set a
| |
Downloading binary content is as simple as providing an
|
Select lists usually contain a set of related select items, which are used in GUIs to enable the user to make a selection of one or more of these items. [fleXive] allows in-memory creation of slim select lists for quick GUI display, as well as defining and persisting fully fledged deeply nested select lists. Names of selectlist items have to be unique within their respective list.
The following is a list of parameters that can be passed as arguments to
FxSelectListEdit
when editing or creating a new select list:
Parameter | Method | Description |
---|---|---|
Parent list |
-
|
Set the parent list of this select list (used for nested select lists). Can only be set when the select list is created. |
Name |
setName(String name)
|
Set the name of the select list (has to be unique). |
Label |
setLabel(FxString label)
|
Set a label text to be displayed in user interfaces. |
Description |
setDescription(FxString description)
|
Set a description text to be displayed in user interfaces. |
Allow dynamic item creation |
-
|
May items be created dynamically (in UIs other than the administration GUI). Can only be set when the select list is created. This flag is merely used as information for UI's where users may create select list items themselves. Independent of this flag the users can only create items if they have the permission (see Table 6.7, “Relevant permissions for working with select list items” for details). |
Create Item ACL |
-
|
The ACL which controls the permissions for adding and removing select items to the select list. Can only be set when the select list is created. |
New Item ACL |
-
|
The ACL which is assigned to newly created items by default. Can only be set when the select list is created. |
Default Item |
setDefaultItem(FxSelectListItem defaultItem)
|
A select list item, which is selected by default. |
The following is a list of parameters that can be passed as arguments to
FxSelectListItemEdit
when editing or creating a new select list item:
Parameter | Method | Description |
---|---|---|
List |
-
|
The select list to which this select item belongs. |
Name |
setName(String name)
|
Set the name of the item (has to be unique within the assigned list). |
Parent Item |
setParentItem(FxSelectListItem item)
|
Set the parent item of this select list item (used for nested select lists). |
ACL |
setAcl(ACL acl)
|
The ACL of the select item (see Table 6.7, “Relevant permissions for working with select list items” for details). |
Label |
setLabel(FxString label)
|
Set a label text to be displayed in user interfaces. |
Data |
setData(String data)
|
Set additional data stored in the select item. |
Color |
setColor(String color)
|
Set the item's display color. |
Icon Id |
setIconId(long iconId)
|
Set the id of this select list item's icon. |
Icon version |
setIconVer(int iconVer)
|
Set the version of the icon to be displayed. |
Icon quality |
setIconQuality(int iconQuality)
|
Set the quality of the icon to be displayed. |
The item's Life Cycle Information getLifeCycleInfo()
is generated and managed by
the database and can not be edited.
As mentioned earlier, two kinds of select lists can be created. The first kind is
not suitable for being persisted and is used for example for quick display
in UI input components. FxSelectList
provides
FxSelectList(String name)
,
createList(String name, List<? extends SelectableObjectWithLabel> items)
and
createListWithName(String name, List<? extends SelectableObjectWithName> items)
for these purposes. FxSelectListItem
provides
FxSelectListItem(long id, FxSelectList list, long parentItemId, FxString label)
for select list items that are not persisted.
The second kind of select lists, which can be persisted, are created via FxSelectListEdit
and
its constructor or createNew(..)
helper methods.
Similar to persistable select lists, persistable select list items are created via
the FxSelectListItemEdit
class by invoking its constructor or its
createNew(..)
method.
The persistance is handled via methods provided
by theSelectListEngine
.
While only users in the role of SelectListEditor may create, update and delete select lists, select list items are handled differently. Whether a specific user is permitted to add itmes to and remove items from a specific select list is handled by the createItem ACL of the select list. Whether users may read, edit, select and deselect a specific select list item is handled by the ACL of the select item itsself. The operations and relevant permissions are specified in Table 6.7, “Relevant permissions for working with select list items”.
Operation | ACL | Permission | Description |
---|---|---|---|
Creating a select list item | FxSelectList.createItemACL | CREATE |
The createItemACL of the item's select list controls which users
may create and hence add select list items to this specific select list.
|
Deleting a select list item | FxSelectList.createItemACL | DELETE |
Similar to the creation of new select list items, the createItemACL
of the item's select list also controls which users
may remove select list items from this specific select list.
|
Editing a select list item | FxSelectListItem.acl | EDIT | Whether a user may change the data of a specific select list item is controlled by the EDIT permission of the ACL of the select list item itsself. |
Reading a select list item | FxSelectListItem.acl | READ | Whether a user may read a specific select list item and its data (for exmaple in the content editor) is controlled by the READ permission of the select list item. |
Adding a select list item to a selection (when working with contents) | FxSelectListItem.acl | READ, CREATE | Whether a user may add specific select list item to his seleciton is controlled by the READ (otherwise the user wouldn't see that the item exists) and by the CREATE permission of the select list item. |
Removing a select list item to a selection (when working with contents) | FxSelectListItem.acl | READ, DELETE | Whether a user may remove specific select list item from his seleciton is controlled by the READ (otherwise the user wouldn't see that the item exists) and by the DELETE permission of the select list item. |
Multiplicity - or often referred to as
cardinality
- defines the minimum and maximum occurance of an assignment. An assignment in the context of [fleXive] is a
group- or a property assignment. Multiplictiy is implemented in the class
FxMultiplicity
which contains some predefined and often used constants:
FxMultiplicity.MULT_0_1
: zero or one occurances (optional)
FxMultiplicity.MULT_1_1
: exactly one occurance (required)
FxMultiplicity.MULT_0_N
: zero or more occurances (optional)
FxMultiplicity.MULT_1_N
: one or more occurances (required)
The value
N
means any number of occurances.
A multiplicity of 1 to 5 elements would be coded like this:
new FxMultiplicity(1,5)
A property defines a name and a datatype (and some options). It can only exist (and is of relevance) if it is assigned to a type or group. The purpose of keeping properties and their assignments separate is the ability to share them and query across multiple types with a single property.
There are two ways to assign a property to an existing type or group:
Either by calling
FxPropertyEdit.createNew(..)
method which can clone existing or create entirely
new properties or by reusing an existing property assignment by calling
FxPropertyAssignmentEdit.createNew(..)
.
Example 6.7. Creating new properties
AssignmentEngine assignmentEngine = EJBLookup.getAssignmentEngine(); ACL customerACL = CacheAdmin.getEnvironment().getACL(ACLCategory.STRUCTURE.getDefaultId()); FxPropertyEdit name = FxPropertyEdit.createNew("Name", new FxString("Name of the person"), new FxString("Enter the persons name"), FxMultiplicity.MULT_1_1, customerACL, FxDataType.String1024); assignmentEngine.createProperty(typeId, name.setAutoUniquePropertyName(true), "/");
Obtain a reference to the assignment engine bean which is responsible for manipulating assignments | |
Get the default ACL used for structures | |
Create a new property with the alias "Name" | |
Label | |
Hint for user interfaces | |
Configure this property to be required (See the section called “Multiplicity” for more information) | |
Assign the ACL to be used. This ACL will only be checked if the type this property will be assigned to has property permission checks enabled | |
The data type will be a String with a maximum length of 1024 characters. See the section called “Data types” for an overview of available data types. | |
Since properties can not exist if they are not assigned to a type, we assign them to the type
with the id
|
To reuse an existing property-assignment is even simpler:
Example 6.8. Reusing property assignments
assignmentEngine.save( FxPropertyAssignmentEdit.reuse( "ROOT/CAPTION", "Customer", "/", "AnotherCaption"), false);
Obtaining a reference to the assignment engine bean is omitted in this example. We use the
| |
The convenience factory method
| |
The XPath of the assignment that is to be reused in, preceeded by the type. Here we reuse the "Caption" property that is assigned to the virtual Root-Type which acts as a repository (see the section called “Root Type” for more information about the virtual root type). | |
The type we want to assign it to. Please note that the type name is not case sensitive. | |
The new parent XPath relative to the type. Since want to assign it to the root group we use "/". Would we want to assign the property to a group called "Info" which is a subgroup of a group named "About", we'd use the XPath "/About/Info". | |
The
| |
This boolean parameter is used if the assignment is a group assignment. If set to |
One of the most important concepts of [fleXive] is the relation between properties (or groups) and their assignments to types (or groups). As mentioned in the introduction to this chapter: "A property defines a name and a datatype (and some options). It can only exist (and is of relevance) if it is assigned to a type or group. The purpose of keeping properties and their assignments separate is the ability to share them and query across multiple types with a single property."
Essentially this means, that while a property does have unique attributes (which can be overwritten), its assignments to different types imply that these attributes can differ from the "original". As soon as a property has no more assignments (i.e. is no longer associated to a type), it is removed from [fleXive] The ability to further assign the same property to multiple types enables [fleXive] to carry out queries for these properties and returning results from any type they are attached to.
A simple, theoretical example:
Given the types "A" and "B", and property "T" having its label set to "foo".
First, "T" is assigned to "A"
Second, "T" is assigned to "B" and the assignment's label set to "bar".
Step I.) Querying "T"'s label (i.e. loading the FxProperty
) will yield "foo".
Step II.) Querying for "T"'s assignment to "B" will yield "bar".
Step III.) After deleting the assignment of "T" to "A", the query in Step I.) will still yield "foo".
This concept is best explained by giving a comprehensive example using actual [fleXive] code: The types "Person" and "Anotherperson" are created. The property firstname will first be assigned to "Person", then an assignment of the same property is made to "Anotherperson". The original property assignment is then removed from "Person" showing that the property will still retain the attributes it received during creation.
Please note that the concepts explained here also apply to groups and their assignments.
Example 6.9. Property assignment concepts
import com.flexive.shared.scripting.groovy.* import com.flexive.shared.value.* import com.flexive.shared.security.* import com.flexive.shared.* import com.flexive.shared.structure.* new GroovyTypeBuilder().person(label: new FxString("Person"), acl: CacheAdmin.environment.getACL(ACLCategory.STRUCTURE.defaultId), multilang: true) { } // we "reload" the "Person" type to show the means of adding properties using the // GroovyTypeBuilder after type creation. def builder = new GroovyTypeBuilder("Person") builder { firstname(dataType: FxDataType.String1024, multilang: false, label: new FxString(FxLanguage.ENGLISH, "A person's first name"), multiplicity: FxMultiplicity.MULT_0_N) } new GroovyTypeBuilder().anotherperson(label: new FxString("Anotherperson"), acl: CacheAdmin.environment.getACL(ACLCategory.STRUCTURE.defaultId), multilang: true) { anotherfirstname(assignment: "PERSON/FIRSTNAME", label: new FxString(FxLanguage.ENGLISH, "Another's first name")) } def name = "" def type = CacheAdmin.getEnvironment().getType("person") FxPropertyAssignment propAssign = type.getPropertyAssignment("PERSON/FIRSTNAME") name = propAssign.getLabel() EJBLookup.getAssignmentEngine().removeAssignment(propAss.getId(), false, false); FxProperty prop = CacheAdmin.getEnvironment().getProperty("firstname"); return "Removed assigned (label): " + name + "; Retained label for property: " + String.valueOf(prop.getLabel())
The type "Person" is created. | |
The
| |
Here we create / assign the property "firstname" and .. | |
.. set its label to "A person's first name". Note that the
| |
The type "Anotherperson" is created .. | |
.. and the firstname property is assigned to this type having the alias "anotherfirstname". | |
The label is set to "Another's first name". | |
After temporarily storing the property's label (for later reference) we remove the assignment of the property "firstname" from the type "Person". | |
Since only the assignment was removed, we can still load the "original" property. | |
We can then return both the assignment's label which was just removed, and for comparison
reasons the label of the "stand-alone" property,
showing they will be the same. The script will return the text:
|
The following is a list of parameters that can be passed as arguments to
FxPropertyEdit
and
FxPropertyAssignmentEdit
when editing or creating a new propery/assignment:
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
ACL |
setACL(ACL acl)
|
X | X | The ACL which is checked when the type using this property or assignment is configured
to check property permissions. Setting this value for
FxPropertyAssignmentEdit
is only allowed if the referenced property allows to override its ACL.
|
Hint |
setHint(FxString hint)
|
X | X | Set a hint text to be displayed in user interfaces. |
In overview |
setInOverview(boolean inOverview)
|
X | X | Display in overviews. This is an option for user interfaces and a convenience method to
set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_SHOW_OVERVIEW
("SHOW.OVERVIEW" ) is used. The property can restrict this setting
from being overwritten in an assignment.
|
Label |
setLabel(FxString label)
|
X | X | Set a label text to be displayed in user interfaces. |
Multilingual |
setMultiLang(boolean multiLang)
|
X | X | Allow multilingual values for this property. This is a convenience method to
set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_MULTILANG
("MULTILANG" ) is used. The property can restrict this setting
from being overwritten in an assignment.
|
Multiline |
setMultiLine(boolean multiLine)
|
X | X | A hint for user interfaces if this property should be rendered using input elements with
multiple lines. Useful for String/Text based properties (See
the section called “Data types”) which should be displayed in a
textarea instead of a single input field. Decision how to render the component is up to
the user interface. This is a convenience method to
set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_MULTILINE
("MULTILINE" ) is used. The property can restrict this setting
from being overwritten in an assignment.
|
Multiplicity |
setMultiplicity(FxMultiplicity multiplicity)
|
X | (X) | Set the multiplicity of this property. Can only be changed if no instances exist that would violate the new setting. (See the section called “Multiplicity” for more information). The property can restrict this setting from being overwritten in an assignment. |
Options |
setOption(..)
setOptionOverridable(..)
clearOption(..)
|
X | X | Option related operations. Seethe section called “Property and group options”. |
Searchable |
setSearchable(boolean searchable)
|
X | X | Allow user interfaces to use this propery/assignment in visual query editors.
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_SEARCHABLE
("SEARCHABLE" ) is used.
|
Use HTML editor |
setUseHTMLEditor(boolean useHTMLEditor)
|
X | X | Hint for user interfaces to use a HTML editor when editing values of this property. Only
makes sense for String/Text based data types.
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_HTML_EDITOR
("HTML.EDITOR" ) is used.
|
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
Auto unique property name |
setAutoUniquePropertyName(boolean autoUniquePropertyName)
|
X | - |
Property names have to be unique to allow querying them. Setting this option to
true
will automatically choose a name that has not been used for a propery by adding an
underscore and a running number to property names until it is unique. Set this option
only if you do not plan on "sharing" a property between different types or dont need
to query based on properties but rather property assignments.
|
Data type |
setDataType(FxDataType dataType)
|
X | - | Set the data type of this property. Please see the section called “Data types” for more information. |
Fulltext indexed |
setFulltextIndexed(boolean fulltextIndexed)
|
X | X | Enable fulltext indexing and queries for a property. See the section called “Fulltext search” for more information. |
Name |
setName(String name)
|
X | - | Set the name of this property. This name is used in assignments as a proposal for the XPath alias (unless a different one is requested). Currently the name can not be changed for existing properties. To query across assignments using the same property, this name is used. |
Overridable ACL |
setOverrideACL(boolean overrideACL)
|
X | X | Restrict if assignments may use an ACL different from the one defined for the property.
If set to
false
an assignment may still set an ACL but the ACL of the property is used and the
assignments is ignored.
|
Overridable HTML editor |
setOverrideHTMLEditor(boolean overrideHTMLEditor)
|
X | X | Restrict assignment to override the HTML editor option (User interface hint).
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_HTML_EDITOR
("HTML.EDITOR" ) is used.
|
Overridable Multilinguality |
setOverrideMultiLang(boolean overrideMultiLang)
|
X | X | Restrict assignment to override the multilinguality option (allow multilingual values).
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_MULTILANG
("MULTILANG" ) is used.
|
Overridable Multiline |
setOverrideMultiLine(boolean overrideMultiLine)
|
X | X | Restrict assignment to override the multiline option (User interface hint).
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_MULTILINE
("MULTILINE" ) is used.
|
Overridable multiplicity |
setOverrideMultiplicity(boolean overrideMultiplicity)
|
X | X | Restrict if assignments may override the multiplicity of this property. (See the section called “Multiplicity” for more information). |
Overridable Overview |
setOverrideOverview(boolean overrideOverview)
|
X | X | Restrict assignment to override the overview option (User interface hint).
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_SHOW_OVERVIEW
("SHOW.OVERVIEW" ) is used.
|
Overridable Searchable |
setOverrideSearchable(boolean overrideSearchable)
|
X | X | Restrict assignment to override the searchable option (User interface hint).
This is a convenience method to set an option (See
the section called “Property and group options”). The constant
FxStructureOption.OPTION_SEARCHABLE
("SEARCHABLE" ) is used.
|
Referenced list |
setReferencedList(FxSelectList referencedList)
|
X | (X) | If the properties data type is
SelectOne
or
SelectMany
(See
the section called “Data types”
for more information) the referenced selectlist (See
the section called “Select lists”) can be assigned. Updating an existing
property is only allowed if no data instances using the original selectlist exist.
|
Referenced type |
setReferencedType(FxType referencedType)
|
X | (X) | If the properties data type is
Reference
(See
the section called “Data types”
for more information) the referenced type (See
the section called “Types”) can be assigned. Updating an existing
property is only allowed if no data instances using the original type exist.
|
Unique mode |
setUniqueMode(UniqueMode uniqueMode)
|
X | (X) | Set the uniqueness level of this property. May only be changed if no content instances using this property exist. (See the section called “Uniqueness of values” for more information). |
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
Alias |
setAlias(String alias)
|
X | - | Set the alias of a property assignment. Property assignments may define an alias to allow multiple use of the same property but using a different name. The alias is the rightmost part of the XPath used to address an assignment. Changing an alias for existing assignments is not supported (yet). |
Default language |
setDefaultLanguage(int language)
|
X | X | Defining a (optional) default language preselects this language in multilingual values as the default language. |
Default multiplicity |
setDefaultMultiplicity(int defaultMultiplicity)
|
X | X | The default multiplicity determines how many values will be initialized for an assignment. Useful in user interfaces to pre-create a set of entries instead of one. |
Enabled |
setEnabled(boolean enabled)
|
X | (X) | Enables or disables a property assignment - making it unavailable to editors, etc. Updating an existing assignment is currently experimental and might have side-effects ... |
Parent group assignment |
setParentGroupAssignment(FxGroupAssignment parent)
|
X | - | If this assignment is assigned to a group, the assignment of the parent group (in the context of the current type) |
Position |
setPosition(int position)
|
X | X | Set the position of the assignment (within the same parent group). Changing an assignment's position will be update all other affected assignments within the same group. Invalid values will be adjusted (to 0 or the max. possible position) |
[fleXive] supports the following modes to enforce that a value is unique:
None
: No uniqueness is enforced
Global
: Globally unique across all usages of a property
Type
: Unique within all instances of a type
DerivedTypes
: Unique within all instances of a type, its parents and
types derived from it
Instance
: Unique within a content instance
A group basically only defines a name (and some options). It can only exist (and is of relevance) if it is assigned to a type or another group. The purpose of keeping groups and their assignments separate is the ability to share them and be consistent with how properties and property assignments are handled.
Just like using properties, there are two ways to assign a group to an existing type or another group:
Either by calling
FxGroupEdit.createNew(..)
method which can clone existing or create entirely
new groups or by reusing an existing group assignment by calling
FxGroupAssignmentEdit.createNew(..)
.
Example 6.10. Creating a new group
AssignmentEngine assignmentEngine = EJBLookup.getAssignmentEngine(); assignmentEngine.createGroup( typeId, FxGroupEdit.createNew( "Address", new FxString("The customers address"), new FxString("Enter the customers address here"), true, FxMultiplicity.MULT_1_1). setAssignmentGroupMode(GroupMode.AnyOf), "/"); FxPropertyEdit street = FxPropertyEdit.createNew(...); FxPropertyEdit zip = FxPropertyEdit.createNew(...); assignmentEngine.createProperty(typeId, street, "/Address"); assignmentEngine.createProperty(typeId, zip, "/Address");
Obtain a reference to the assignment engine which is needed to create groups, properties and (of course) assignments | |
We're about to create a new group | |
Since groups can not be created without assigning them to a type, we have to provide the id of the type we want to assign this group to. | |
The second parameter to
| |
"Address" is the name we chose for the new group | |
The label (for user interfaces) | |
The hint (for user interfaces again) | |
This parameter allows overriding the multiplicity assigned in the next line by assignments to the group | |
We make the group required, setting the multiplictiy to 1..1 (See the section called “Multiplicity” for more information) | |
This parameter is optional, since it is the default value. We set the group mode to allow
any
of the group's children to be present. An alternative would be
| |
We need to provide the XPath relative to the root group of the type where we want to assign the group to. Using "/" will assign it directly to the root group. | |
We create a property called "Street" which we want to assign to the address group later. | |
Same for the property "ZIP" | |
The "Street" property is created like in the section called “Properties and property assignments”, but we assign it to our new created group "/Address" | |
And again for the "ZIP" code |
Here's another example for creating groups using the
GroovyTypeBuilder
and for attaching content using the GroovyContentBuilder
:
Example 6.11. Creating a new group using the
GroovyTypeBuilder
import com.flexive.shared.scripting.groovy.* import com.flexive.shared.value.* import com.flexive.shared.security.* import com.flexive.shared.* import com.flexive.shared.structure.* new GroovyTypeBuilder().person(label: new FxString("Person"), acl: CacheAdmin.environment.getACL(ACLCategory.STRUCTURE.defaultId), multilang: true) { firstname(dataType: FxDataType.String1024, multilang: false, label: new FxString(FxLanguage.ENGLISH, "First name"), multiplicity: FxMultiplicity.MULT_0_N) lastname(assignment: "PERSON/FIRSTNAME", label: new FxString(FxLanguage.ENGLISH, "Last name"), hint: new FxString(FxLanguage.ENGLISH, "Last name required"), multiplicity: FxMultiplicity.MULT_1_N) ADDRESS(label: new FxString(FxLanguage.ENGLISH, "Address"), multiplicity: FxMultiplicity.MULT_0_N) { street(dataType: FxDataType.String1024, label: new FxString(FxLanguage.ENGLISH, "Street (Nr)"), multiplicity: FxMultiplicity.MULT_0_N) } } def builder = new GroovyContentBuilder("PERSON") builder { firstname("John") lastname("Doe") address { street(new FxString(false, "Ameaningfulstreetname 444")) } } EJBLookup.getContentEngine().save(builder.getContent())
Create the type "Person" using the
| |
.. use the default ACLs .. | |
.. and set the type to support multiple languages. | |
Create the first property "firstname". | |
Another property for the last name (implicitly required because auf the default multiplicity of 1..N), which is a derived assignment from "FIRSTNAME". | |
Here, the group "Address" having the XPath "ADDRESS" is created. Important: UPPERCASE LETTERS (Either the whole group name or simply the first letter, as in "Address") always denote the creation of a Group. | |
The group's only property: "street". | |
Retrieve a
| |
Call the builder passing the parameters (XPathname([contentValue]): | |
Set the firstname to "John". | |
Set the lastname to "Doe". | |
"Open up" the group's XPath value using "address". | |
Pass the value "Ameaningfulstreetname 444" to the XPath ADDRESS/STREET | |
Save the content by retrieving the ContentEngine EJB and calling its
|
The following is a list of parameters that can be passed as arguments to
FxGroupEdit
and
FxGroupyAssignmentEdit
when editing or creating a new group/assignment:
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
Assignment GroupMode |
setAssignmentGroupMode(GroupMode mode)
|
X | (X) | Set the group mode to allow any of its possible children or just one to be present. Can only be changed for existing groups/assignments if no instances exist (See the section called “Group modes” for more information) |
Hint |
setHint(FxString hint)
|
X | X | Set a hint text to be displayed in user interfaces. |
Label |
setLabel(FxString label)
|
X | X | Set a label text to be displayed in user interfaces. |
Multiplicity |
setMultiplicity(FxMultiplicity multiplicity)
|
X | (X) | Set the multiplicity of this group. Can only be changed if no instances exist that would violate the new setting. (See the section called “Multiplicity” for more information). The group can restrict this setting from being overwritten in an assignment. |
Options |
setOption(..)
setOptionOverridable(..)
clearOption(..)
|
X | X | Option related operations. Seethe section called “Property and group options”. |
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
Name |
setName(String name)
|
X | - | Set the name of this group. This name is used in assignments as a proposal for the XPath alias (unless a different one is requested). Currently the name can not be changed for an existing group. |
Overridable multiplicity |
setOverrideMultiplicity(boolean overrideMultiplicity)
|
X | X | Restrict if assignments may override the multiplicity of this group. (See the section called “Multiplicity” for more information). |
Parameter | Method | Create | Edit | Description |
---|---|---|---|---|
Alias |
setAlias(String alias)
|
X | - | Set the alias of a group assignment. Group assignments may define an alias to allow multiple use of the same group but using a different name. The alias is part of the XPath and is used to address an assignment. Changing an alias for existing assignments is not supported (yet). |
Default multiplicity |
setDefaultMultiplicity(int defaultMultiplicity)
|
X | X | The default multiplicity determines how many values will be initialized for an assignment (i.e. how many groups are created upon initialization). Useful in user interfaces to pre-create a set of entries instead of one. |
Enabled |
setEnabled(boolean enabled)
|
X | (X) | Enables or disables a group assignment - making it unavailable to editors, etc. Updating an existing assignment is currently experimental and might have side-effects ... |
Parent group assignment |
setParentGroupAssignment(FxGroupAssignment parent)
|
X | - | If this assignment is assigned to a group, the assignment of the parent group (in the context of the current type) |
Position |
setPosition(int position)
|
X | X | Set the position of the assignment (within the same parent group). Changing an assignments position will be upate all affected other assignments within the same group. Invalid values will be adjusted (to 0 or the max. possible position) |
[fleXive] supports the two modes for groups
OneOf
andAnyOf
:
OneOf
: Only one of the groups children may be present, honoring their
regular indices. This mode only makes sense if all subgroups/properties are optional!
AnyOf
: Any of the groups children may be present, honoring their regular
indices. This is the default setting.
Both properties and groups allow the definition of options. These options can hold any arbitrary
String
or
Boolean
value and, if defined, the assignments to the property or group may override the value. The name of an option
must be unique.
See the API documentation of class FxStructureOption
for more details.
The following options are currently actively supported:
Constant Value | Description |
---|---|
MULTILANG |
Value supports multiple languages (
true
/
false
)
|
SHOW.OVERVIEW |
Values are shown in UI overview components (
true
/
false
)
|
HTML.EDITOR |
Value can be edited using an HTML editor in user interfaces (
true
/
false
)
|
SEARCHABLE |
Values can be queried (this is just a hint for user interfaces!) (
true
/
false
)
|
MAXLENGTH |
Values that support a maximum input length (currently only
String1024
and
Text
) will be rendered with input length restrictions when editing.
|
MULTILINE | Render a textarea instead of a single input line. If the value is greater than 1 it determines the number of rows. |
REFERENCE.SELECTONE | Render a select list with all valid choices for reference properties (properties referencing other contents). |
SELECTMANY.CHECKBOXES | Render checkboxes instead of a multi-select list for FxSelectMany properties. |
The
GroovyTypeBuilder
("GTB")
provides a simple means for structure creation in [fleXive] using the Groovy scripting language.
The GTB is based on Groovy's builder support, enabling us to easily create and manipulate [fleXive]'s
hierarchical structures.
Here is what the GTB can do (for you):
Structural or assignment changes pertain to any element within an existing type, with the exception of types themselves (please refer to the examples in the section called “GroovyTypeBuilder Usage Examples” for further reference).
A simple example of the GTB can be seen below. We create the type "PERSON" having one attribute "NAME":
Example 6.12. Creating a simple type with one attribute
import com.flexive.shared.scripting.groovy.* import com.flexive.shared.value.* import com.flexive.shared.security.* import com.flexive.shared.* import com.flexive.shared.structure.* new GroovyTypeBuilder().person { name() }The type and its attribute were created using the default settings for both types and properties (i.e. for the "NAME" this means the
FxDataType
"String")
More on default settings and all available attributes can seen in
the section called “GroovyTypeBuilder Attributes”
and in
the section called “Property and Group Creation - Default Values”.
If you would like to get right into the thick of it, please check out the example section
the section called “GroovyTypeBuilder Usage Examples”.
Based on Groovy, a familiarity with its syntax is an asset, but not a requirement to understand the very simple syntax rules for the GTB.
General rules:
Groupname { }or have parentheses w/o curly braces, as in
Groupname ()
propertyname (label: new FxString("Property label"), multilang: false)
Creation and change of structural elements
GroovyTypeBuilder
's constructor,
giving the type's name as the build parameter (e.g.: type name = "BLOG"
new GroovyTypeBuilder().blog { }or
new GroovyTypeBuilder().blog()or by assigning a builder variable:
def builder = new GroovyTypeBuilder() builder.blog { }
new GroovyTypeBuilder().blog(label: new FxString(true, "A Blog Type"), trackHistory: true, historyAge: 10L) { }or
def builder = new GroovyTypeBuilder() builder.blog(label: new FxString(true, "A Blog Type"), trackHistory: true, historyAge: 10L) { // ... properties & groups here ... }
new GroovyTypeBuilder().blog { title() Entry { text() } }
Loading a type (more on this in the section called “GroovyTypeBuilder Usage Examples”.
Types can either be loaded by passing the type's name to the GTB as in the following example, e.g. loading the type "BLOG"
def builder = new GroovyTypeBuilder("BLOG") builder { // do something with "BLOG" }
Alternatively (and quite useful if you do a lot of "copy-and-paste" with your script code), the type can also be loaded using the already presented constructor: When called, the type will be loaded if it already exists, otherwise a new type bearing the given name will be created.
// "BLOG" already exists def builder = new GroovyTypeBuilder().blog { // do something with "BLOG" }
def builder = new GroovyTypeBuilder("BLOG") builder { 'abstract'(label: new FxString(true, "Abstract Prop"), dataType: FxDataType.Text) }
The following is a list of all available attributes for the
GroovyTypeBuilder
.
The parameters correspond to the type/property/group parameters mentioned in
the section called “Structure Engine”
Parameters / attributes are split up into the following categories:
As mentioned inthe section called “GroovyTypeBuilder Syntax”, all attributes are called via the following syntax:
[STRUCTURENAME] ([attribute]: [value] [, ..])
E.g:
firstname(multiLang: false,
label: new FxString(true, "First name"))
Attributes in the wrong case will be ignored, misspelled attributes *might* be interpreted as generic structure options.
Override options which are not explicitly set will by default return "true". The following overrides are affected: "overrideMultiplicity", "overrideACL", "overrideSearchable", "overrideMultiline", "overrideInOverview", "overrideMultilang", "overrideMaxLength", "overrideUseHtmlEditor"
Guarantee: The GTB guarantees that changes to assignments will only affect the attributes parameterised in the call to the GTB. (i.e. a change to the "label" has no effect on any other attributes, an "empty" call to an existing assignment does not affect the assignment at all).
Hint: Examples might omit part of the code.
Attribute | Input | Example | Description |
---|---|---|---|
acl |
String
or
ACL
|
testtype(acl: "Default Structure ACL")
or
testtype(acl:
CacheAdmin.getEnvironment().getACL(ACLCategory.STRUCTURE.getDefaultId())
|
Sets the access control list for the given type. If not given, the "Default Structure ACL" is used |
generalACL |
String
or
ACL
|
new GroovyTypeBuilder().testtype(acl: "Default Structure ACL", generalACL: "Custom ACL") {
prop1()
prop2(acl: "Default Structure ACL")
}
|
Sets a general (ACLCategory.STRUCTURE) ACL which is valid for all (newly) created property assignments within the type. A given "acl" will override the "generalACL" |
defaultInstanceACL |
String
or
ACL
|
Providing an instance ACL named "Foobar Instance ACL" exists:
new GroovyTypeBuilder().testtype(defaultInstanceACL: "Foobar Instance ACL") {
...
}
|
Sets a default content instance ACL for the given typ |
label |
FxString
|
testtype(label: new FxString(true, "Property 01"))
|
Sets the type's label. If not given, the element's name is used (code example: "testtype" |
parentTypeName |
String
|
testtype(parentTypeName: "ROOT")
|
Creates a derived type from the given parentTypeName. |
languageMode |
LanguageMode
|
testtype(languageMode: LanguageMode.Single
|
Determines how the type handles languages |
typeMode |
TypeMode
|
testtype(typeMode: TypeMode.Relation)
|
Sets the mode of an FxType |
trackHistory |
Boolean
|
testtype(trackHistory: true)
|
Enables history tracking for a type. |
historyAge | Long |
testtype(trackHistory: true, historyAge: 10L)
|
Sets the number of history entries. Only used in conjunction with "trackHistory" |
maxVersions | Long |
testtype(maxVersions: 5L)
|
Sets the number of versions to keep. |
useInstancePermissions |
Boolean
|
testtype(useInstancePermissions: true)
|
Use instance permissions |
usePropertyPermissions |
Boolean
|
testtype(usePropertyPermissions: true)
|
Use property permissions |
useStepPermissions |
Boolean
|
testtype(useStepPermissions: true)
|
Use step permissions |
useTypePermissions |
Boolean
|
testtype(useTypePermissions: true)
|
Use type permissions |
usePermissions |
Boolean
|
testtype(usePermissions: true)
|
Use all permissions if set to "true" |
workflow |
String
or
Workflow
|
testtype(workflow: "Editor Workflow")
|
Set the given Workflow for the type (Workflow must exist) |
[GENERIC STRUCTURE OPTION] |
String
|
new GroovyTypeBuilder().ford(COLOUR:"black")
|
Set a generic option for the given type |
[GENERIC STRUCTURE OPTIONS] as a List : "structureOptions" |
List<FxStructureOption>
|
|
Set the type's options via a List of FxStructureOptions. The structureoptions can, for instance,
be created using the GroovyOptionBuilder (refer to JavaDoc f. instructions)
|
icon |
FxReference
|
testtype(icon: new FxReference([example omitted for brevity]...))
|
Set an icon for the given type |
Attribute | Input | Example | Description |
---|---|---|---|
label |
FxString
|
prop(label: new FxString(true, "Property 01"))
|
Sets the property's label. If not given, the element's name is used (code example: "prop") |
name |
String
|
testprop(name: "myprop")
Will create a property named "MYPROP".
W/o the "name" attribute, the property's name would be "TESTPROP"
|
Set the property's or group's name. The name attribute will override any name given during structure creation. |
alias |
String
|
address(alias: "address_a")
(will create the XPath assignment "TYPENAME/ADDRESS_A"
|
Set the alias for a given property or group. Will affect the XPath! |
hint |
FxString
|
Address(hint: new FxString(true, "Contains address properties"))
|
Set the property's or group's hint attribute |
multiplicity |
FxMultiplicity
or
String
|
phonenumber(multiplicity: "0,3")
|
Set the property's or group's multiplicity (cardinality). A default of 0..1 is assumed |
defaultMultiplicity |
Integer
|
Address(defaultMultiplicity: 0)
|
Set a property's or group's default multiplicity. A default of 1 is assumed |
overrideMultiplicity |
Boolean
|
street(overrideMultiplicity: false)
|
Set whether the property's or group's assignment may override the base multiplicity. A default of "true" is assumed for properties, "false" for groups. |
[GENERIC STRUCTURE OPTION] |
String
|
Address(label: new FxString("Address Group")
"BUSINESS": true)
or
Address(label: new FxString(" Address Group")
BUSINESS: "Telecom provider")
|
Set a generic option for the given property |
[GENERIC STRUCTURE OPTIONS] as a List : "structureOptions" |
List<FxStructureOption>
|
|
Set the group's or property's options via a List of FxStructureOption s.
|
Attribute | Input | Example | Description |
---|---|---|---|
acl |
String
or
ACL
|
street(acl: "Default Structure ACL")
or
street(acl:
CacheAdmin.getEnvironment().getACL(ACLCategory.STRUCTURE.getDefaultId())
|
Sets the ACL for the given property. By default the "Default Structure ACL" is used. |
overrideACL |
Boolean
|
street(acl: "Default Structure ACL",
overrideACL: true)
|
The property's assignments may override the property's ACL |
dataType |
FxDataType
|
htmlEdit(dataType: FxDataType.HTML)
|
Set the datatype for the given property. If not given,
FxDataType.String1024
is assumed
|
autoUniquePropertyName |
Boolean
|
name(autoUniquePropertyName: false)
|
Automatically creates a unique property name should the same property (name) exist already. By default the attribute is "true" |
fullTextIndexed |
Boolean
|
note(dataType: FxDataType.Text, fullTextIndexed: false)
|
Sets the full text search attribute for properties |
multilang |
Boolean
|
title(dataType: FxDataType.String1024, multilang: true)
|
Sets the property's multilanguage attribute |
overrideMultilang |
Boolean
|
title(multilang: false, overrideMultilang: true)
|
Determines if the multilang option may be overriden in assignments |
overrideInOverview |
Boolean
|
title(overrideInOverview: false)
|
Assignments may override the "INOVERVIEW" option |
maxLength |
Integer
|
phonenumber(maxLength: 25, dataType: FxDataType.Text)
|
Restrict the maximum length of input values. Works in conjunction with
FxDataType.String1024
and
FxDataType.Text
|
overrideMaxLength |
Boolean
|
title(overrideMaxLength: false)
|
Assignments may override the "MAXLENGTH" option. |
overrideMultiline |
Boolean
|
title(overrideMultiline: false)
|
Assignments may override the "MULTILINE" option |
overrideSearchable |
Boolean
|
title(overrideSearchable: false)
|
Assignments may override the "SEARCHABLE" option |
overrideUseHtmlEditor |
Boolean
|
htmledit(overrideUseHtmlEditor: false)
|
Assignments may override the html editor option |
searchable |
Boolean
|
htmledit(searchable: false)
|
Property can be searched |
inOverview |
Boolean
|
htmledit(inOverview: true)
|
Property is in overview |
useHtmlEditor |
Boolean
|
numberarea(useHtmlEditor: true, dataType: FxDataType.Number)
|
Property uses the html editor |
multiline |
Boolean
|
numberarea(multiline: true, dataType: FxDataType.HTML)
|
Use a multiline input field for entering values |
defaultValue |
FxValue
|
title(dataType: FxDataType.String1024,
defaultValue: new FxString(false, "Dr."))
|
Sets the default FxValue for the given property. |
uniqueMode |
UniqueMode
|
note(FxDataType.HTML,
uniqueMode: UniqueMode.Global)
|
Set the uniqueness of a property |
referencedType |
FxType
or
String
|
imageref(dataType: FxDataType.Reference,
referencedType: "IMAGE")
or
imageref(dataType: FxDataType.Reference,
referencedType: CacheAdmin.getEnvironment().getType("IMAGE")
|
Sets the referenced FxType for a property |
referencedList |
FxSelectList
or
String
|
country(dataType: FxDataType.SelectOne,
referencedList: "COUNTRIES"
or
country(dataType: FxDataType.SelectOne,
referencedList: CacheAdmin.getEnvironment().getSelectList("COUNTRIES")
|
Sets the FxSelectList for a FxDataType.SelectOne / .SelectMany property |
Attribute | Input | Example | Description |
---|---|---|---|
groupMode |
GroupMode
or
String
|
Address(label: new FxString(true, "Home Address"),
groupMode: GroupMode.OneOf)
or
Address(label: new FxString(true, "Home Address"),
groupMode: "AnyOf")
|
Sets the GroupMode for the given group. |
As is the case with all assignments, the attribute settings are taken from the base assignment, any attributes listed here can be used to change them (e.g. the "label") if applicable (or if overridable)
Attribute | Input | Example | Description |
---|---|---|---|
assignment |
String
|
property(assignment: "ROOT/CAPTION")
|
Create an assignment from an existing property or group assignment by specifying the XPath. When creating group assignments, also consider using "createSubAssignments" (see the the section called “Group Assignment Attributes” for further information on this attribute). |
label |
FxString
|
property(label: new FxString(true, "Property 01"))
|
Set or change the assignment's label |
defaultMultiplicity |
Integer
|
Address(defaultMultiplicity: 0)
|
Set a property's or group's default multiplicity IFF overrideBaseMultiplicity = "true" |
alias |
String
|
address(assignment: "CONTACTDATA/ADDRESS", alias: "address_a")
|
Set the alias for a given property or group. Will also change the XPath. |
hint |
FxString
|
Address(hint: new FxString(true, "Contains address properties"))
|
Set the property or group assignment's hint attribute |
multiplicity |
FxMultiplicity
or
String
|
phonenumber(multiplicity: "0,3")
|
Set the propertys or groups assignment's multiplicity |
enabled |
Boolean
|
alternatePhone(assignment: "CONTACTDATA/ADDRESS/PHONENUMBER", enabled:
false)
|
Disable an assignment |
[GENERIC STRUCTURE OPTION] |
String
|
Address(label: new FxString("Address Group")
"BUSINESS": true)
or
Address(label: new FxString(" Address Group")
BUSINESS: "Telecom provider")
|
Set a generic option for the given assignment |
[GENERIC STRUCTURE OPTIONS] as a List : "structureOptions" |
List<FxStructureOption>
|
|
Set the group's or property's options via a List of FxStructureOption s.
|
Attribute | Input | Example | Description |
---|---|---|---|
multilang |
Boolean
|
title(assinment: "CONTACTDATA/TITLE", multilang: true)
|
Sets the property assignment's multilanguage attribute if overridable |
defaultValue |
FxValue
|
author(assignment: "MYBOOK/AUTHOR",
defaultValue: new FxString(false, "Dr."))
|
Sets the default FxValue for the given assignment. |
acl |
String
or
ACL
|
street(assignment: "CONTACTDATA/ADDRESS/STREET", acl: "Default Structure
ACL")
or
street(assignment: "CONTACTDATA/ADDRESS/STREET", acl:
CacheAdmin.getEnvironment().getACL(ACLCategory.STRUCTURE.getDefaultId())
|
Sets the ACL for the given assignment. |
defaultLanguage |
Long
|
text(defaultLanguage: FxLanguage.GERMAN
|
Set the assignment's default language |
multiline |
Boolean
|
text(multiline: true, dataType: FxDataType.HTML)
|
Use a multiline input field for entering values |
inOverview |
Boolean
|
htmledit(inOverview: true)
|
Property assignment is in overview |
useHtmlEditor |
Boolean
|
numberarea(useHtmlEditor: true, dataType: FxDataType.Number)
|
Property assignment uses the html editor |
maxLength |
Integer
|
textarea(multiline: true, maxLength: 100)
|
Restrict the maximum length of input values. |
searchable |
Boolean
|
htmledit(searchable: false)
|
Property assignment can be searched |
flatten |
Boolean
|
Example: create a property "someprop" and activate the hierarchical storage mode
for its assignment:
new GroovyTypeBuilder().aTypeName() { someprop() someprop(flatten:false) }
|
Activates or deactivates the flatstorage for a given property assignment |
Attribute | Input | Example | Description |
---|---|---|---|
groupMode |
GroupMode
or
String
|
Address(label: new FxString(true, "Home Address"),
groupMode: GroupMode.OneOf)
or
Address(label: new FxString(true, "Home Address"),
groupMode: "AnyOf")
|
Sets the GroupMode for the given group. |
createSubAssignments |
Boolean
|
Address(assignment: "CONTACTDATA/ADDRESS", label: new FxString(true, "Home
Address"),
createSubAssignments: true)
|
Automatically creates all subassignments for the new GroupAssignment from the given base assignment |
A property created w/o any attributes as arguments, e.g.:
new GroovyTypeBuilder { prop1() }
has the following characteristics (incl. assignment attributes):
A group created w/o any attributes as arguments, e.g.:
new GroovyTypeBuilder { Group1() }
has the following characteristics:
Several examples of using the GTB can be found throughout the reference documentation. This section further illustrates the various uses the GTB can be put to when creating or updating structural information in [fleXive].
This example creates a type named "COMPANY", comprised of a "name" attribute (derived from "ROOT/CAPTION" and a "People" group also having a property "Name".
Hint: the "Default [fleXive] imports for Groovy" are taken directly from [fleXive]'s script console. It is assumed that they are present for any further examples in this section.
/* Default [fleXive] imports for Groovy */ import com.flexive.shared.* import com.flexive.shared.interfaces.* import com.flexive.shared.value.* import com.flexive.shared.content.* import com.flexive.shared.search.* import com.flexive.shared.tree.* import com.flexive.shared.workflow.* import com.flexive.shared.media.* import com.flexive.shared.scripting.groovy.* import com.flexive.shared.structure.* import com.flexive.shared.security.* new GroovyTypeBuilder().company { name(assignment: "ROOT/CAPTION") People { name(overrideMultiplicity: true) } }
The GTB can load an existing type and perform a walk through its structure.
A walk through the above structure w/o any arguments will not change any of the given assignments, e.g.:
def builder = new GroovyTypeBuilder("COMPANY") builder { name() People { name() } }
Changing any of a type's assignments is simply a matter of adding the relevant attributes and their respective values t.b. changed. In the following example, we change
def builder = new GroovyTypeBuilder("COMPANY") builder { name(label: new FxString("Company name")) People { name(label: new FxString("Staff member name")) } }
If a single assignment must be changed, there is no need to call all existing properties within a type. However, any parent groups must be called in order to perform the structure walk-through and to point the GTB to the correct element.
Example: change the label from "Staff member name" back to "Staff member".
def builder = new GroovyTypeBuilder("COMPANY") builder { People { name(label: new FxString("Staff member")) } }
Types can also be called to add new elements (properties, groups) to an existing structure.
In this example we create a new group "Departments" in our "COMPANY" type, having a child "name" property.
def builder = new GroovyTypeBuilder("COMPANY") builder { Departments(multiplicity: "0,10") { name(label: new FxString("Dept. name")) } }
Creating subgroups is also quite easy:
def builder = new GroovyTypeBuilder("COMPANY") builder { Departments { DepartmentHeads { name(assignment: "COMPANY/PEOPLE/NAME") } } }
Aliases
Aliases can be assigned during element creation and can also be changed for existing assignments. However, it is not necessary to perform subsequent structure walk-throughs by calling the aliased name (albeit possible).
Example: Create a type "TEST" having a property "NAME" with the aliased name "firstname". This will lead to an XPATH assignment of "TEST/FIRSTNAME" for the given property assignment.
new GroovyTypeBuilder().test { name(alias: "firstname") }
The label can then be changed by employing
def builder = new GroovyTypeBuilder("TEST") builder { name(label: new FxString("First name")) }
Any derived assignments MUST consider the aliased name (or its XPath, respectively):
def builder = new GroovyTypeBuilder("TEST") builder { lastname(assignment: "TEST/FIRSTNAME") }
As mentioned above, an alias can also be changed for existing elements:
def builder = new GroovyTypeBuilder("TEST") builder { name(alias: "name") }
.. which would alter the XPath of the above property assignment to "TEST/NAME"
Aliased assignments from other types
A word of caution: Calling aliased assignments from other types will not work (this mainly has to do with the way the GTB has to "guess" where it is within a structure and what it is looking for & also due to the way that structure traversal works).
Example: A structure with an aliased assignment from "ROOT/CAPTION"
new GroovyTypeBuilder().test { caption(assignment: "ROOT/CAPTION", alias: "caption_alias") }
Now we try to call the same structure again:
def builder = new GroovyTypeBuilder("TEST") builder { caption() }
This yields a NEW property within "TEST" by the name of "CAPTION"
Q: How can I go about changing an aliased assignmnent (from another type)?
A: Use the alias instead of the property's name! Example:
def builder = new GroovyTypeBuilder("TEST") builder { caption_alias(label: new FxString("My derived caption")) }
AutoUniquePropertyName / Alias Caveats
Due to the inherent "update-feature" of the GTB, it is of utmost importance to understand how the Builder handles the creation of properties having the SAME name within a given structure. This is best explained by the following examples.
def builder = new GroovyTypeBuilder().test { prop1() prop1() }
The above example will create "Prop1" having the default attribute values, the second call to prop1() will NEITHER create a new property (unique name: "PROP_1") NOR update the existing one.
def builder = new GroovyTypeBuilder().test { prop1() prop1(dataType: FxDataType.Text) }
In the above example, an attempt is made to create a second property with the autoUniquePropertyName "PROP1_1" This, however, will fail since the generated XPATH for the respective property assignment will be equal to the XPath of the original "PROP1" assignment (XPaths provide a UNIQUE way to address assignments, therefore no equal XPaths can exist within the same hierarchical level).
Hence the correct way to go about this is to use an alias (which will also set the XPath accordingly):
def builder = new GroovyTypeBuilder().test { prop1() prop1(dataType: FxDataType.Text, alias: "prop1alias") }
If, on the other hand, the new property (having the same name as an existing one) resides within a different hierarchical level of the given structure, the alias attribute (i.e. setting a different XPath) can be omitted:
def builder = new GroovyTypeBuilder().test { prop1() Group1 { prop1() } }
Assignment Paths
When creating assignments from properties / groups, either the full XPath or a relative XPath can be used to denote the base assignment. Where "relative" implies, that type names can be omitted.
Example 1: full XPath (capitalising the XPath is not necessary)
def builder = new GroovyTypeBuilder().test { prop1() Group1 { prop1(assignment: "TEST/PROP1") } }
Example 2: "relative" XPath
def builder = new GroovyTypeBuilder().test { prop1() Group1 { prop1(assignment: "/prop1") } }
Create a basic structure with the following layout:
The type's name is "PERSON", the label will be "Person Type"
first name property: name: firstname label: "First name"
last name property: name lastname label: "Last name"
middle name property: derived from first name
note property: text area, multiple languages
address group: contains "postcode", "streetname"
new GroovyTypeBuilder().person(label: new FxString(true, "Person Type")) { firstname(label: new FxString(true, "First name")) lastname(label: new FxString(true, "Last name")) middlename(assignment: "PERSON/FIRSTNAME", label: new FxString(true, "Middle name"), multiplicity: "0,3", defaultMultiplicity: 0) note(dataType: FxDataType.Text, multilang: true, overrideMultilang: true, multiline: true, overrideMultiline: false, label: new FxString(true, "Note"), overrideMultiplicity: true, multiplicity: FxMultiplicity.MULT_0_1) Address { postcode(label: new FxString(true, "Post code")) streetname(label: new FxString(true, "Street")) } }
Alter the above structure by..
FxSelectList
def builder = new GroovyTypeBuilder("PERSON") builder { middlename(enable: false) birthdate(dataType: FxDataType.Date, label: new FxString(true, "Birth date")) Address { note(assignment:"PERSON/NOTE", multilang: false, label: new FxString(true, "Note for Address"), defaultMultiplicity: 0) country(dataType: FxDataType.SelectOne, referencedList: "COUNTRIES", label: new FxString(true, "Country")) phoneno(label: new FxString("Phone number"), maxLength: 15, overrideMaxLength: false) town() } }
The
GroovyOptionBuilder
("GOB")
provides a means for creating List
s of FxStructureOption
s using Groovy.
Just like the GTB, the GOB extends Groovy's builder support class.
Let us get straight to the examples to demonstrate how the GOB works:
Considerations
true
by default
Create an option "FOO" having value "BAR" which cannot be overridden and which is not inherited by derived structures
new GroovyOptionBuilder()."FOO"(value: "BAR", overridable: false, isInherited: false)
Create several options
new GroovyOptionBuilder()."FOO"(value: "BAR", overridable: false, isInherited: false) { "opt1"(value: true, overridable: false, isInherited: true) "opt1.special"(value: true, overridable: true, isInherited: true) "opt2"(value: "20.5", overridable: true, isInherited: false) "Addr.Street"(value: "Broadway", overridable: true, isInherited: true) "Addr.StreetNo"(value: "10", overridable: true, isInherited: false) "Addr.TelNo"(value: "0043123456789") "Addr.Country"(value: "Austria") }
Using the GOB in conjunction with the GroovyTypeBuilder requires usage of Groovy's Eval
class,
or the Eval.me(String expression)
method, respectively.
Basically the call to the GOB remains the same as in the previous examples. Using Eval
however,
the code must be quoted using three sucessive double quotes (Groovy's way to escape any special characters within a String).
A list of caveats for using Eval.me in a call to the GOB:
... structureOptions: Eval.me("""[code goes here...]""")...
Full example:
new GroovyTypeBuilder().mytype( label: new FxString(true, 1, "My type label"), structureOptions: Eval.me("""import com.flexive.shared.scripting.groovy.* new GroovyOptionBuilder()."MYOPT"(value: "1", overridable: true, isInherited: true) { "OTHEROPT.SRGN"(value: "0", overridable: true, isInherited: false) "FOO.BAR"(value: "foobar", overridable: false, isInherited: false) }"""))
[1] Imagine an online-shop scenario with different kinds of articles, each implemented using their own type. Something they have in common is their name. Instead of having to build a query for searching the name property that is an OR-construct including all involved types it would be easier to assign to all types a property called "name" and query this property instead of the assignments.