Composite Objects in MATISSE-Eiffel Binding

1st Edition - September 1998

Contact: nakao@matisse.com
© 1998 Tokyo Gas Co., Ltd.

This note shows how to use the composite objects in MATISSE-Eiffel Binding.

What is composite object?
Composition is a form of aggregation with strong ownership and coincident lifetime of part with the whole. The multiplicity of the aggregate end may not exceed one, because part-objects in a composition are not shared.

Let’s take an example to show how to manipulate composite objects. The example program handles documents which consist of several chapters. Each document has a list of authors. Each chapter consists of several sections which consist of several paragraphs. A paragraph may have a hyperlink to another chapter, section or paragraph. The following list is an ODL (Object Definition Language) definition of this example.

interface DOCUMENT : persistent {
	relationship List<DOC_AUTHOR> authors inverse DOC_AUTHOR::documents;
	relationship List<CHAPTER> chapters[0, -1] inverse CHAPTER::of_document;
	attribute String title;
};

interface DOC_CONTENT : persistent {
	relationship List <DOC_CONTENT> linked_by inverse PARAGRAPH::hyperlinks;
};

interface CHAPTER : DOC_CONTENT : persistent {
	relationship List <SECTION> sections [0, -1]  inverse SECTION::of_chapter;
	relationship DOCUMENT of_document inverse DOCUMENT::chapters;
	attribute String title;
};

interface SECTION : DOC_CONTENT : persistent {
	relationship List <PARAGRAPH> paragraphs [0, -1] inverse PARAGRAPH::of_section;
	relationship CHAPTER of_chapter inverse CHAPTER::sections;
	attribute String title;
};

interface PARAGRAPH : DOC_CONTENT : persistent {
	attribute String text;
	relationship SECTION of_section inverse SECTION::paragraphs;
	relationship List <DOC_CONTENT> hyperlinks inverse DOC_CONTENT::linked_by;
};

interface DOC_AUTHOR : persistent {
	relationship List <DOCUMENT> documents inverse DOCUMENT::authors;
	attribute String name;
};

When a document is not necessary any more, its all chapters, sections and paragraphs are not necessary either in most applications. That is, they have a coincident lifetime. The relationships ‘chapters’, ‘sections’ and ‘paragraphs’ should be defined as composite one. These relationships are called composite relationships.
On the other hands, the relationship ‘authors’ does not have to be a composite one, because an author owns a document but the author and the document do not have a coincident lifetime. The relationship ‘hyperlinks’ does not have to be a composite one either for the same reason. 
The following list is the revised ODL definition. The relationships ‘chapters’, ‘sections’ and ‘paragraphs’ are defined as instances of the class CompositeRelationship which is a subclass of ‘Mt Relationship’. The ODL definition uses the keyword ‘mt_instance_of’ to specify the class of relationship. The definition of the class CompositeRelationship is included in the file mt_eif.odl in the directory odl_include under the MATISSE-Eiffel Binding installation directory.

interface DOCUMENT : persistent {
	relationship List<DOC_AUTHOR> authors inverse DOC_AUTHOR::documents;
	relationship List<CHAPTER> chapters[0, -1] inverse CHAPTER::of_document
	   mt_instance_of CompositeRelationship;
	attribute String title;
};

interface DOC_CONTENT : persistent {
	relationship List <DOC_CONTENT> linked_by inverse PARAGRAPH::hyperlinks;
};

interface CHAPTER : DOC_CONTENT : persistent {
	relationship List <SECTION> sections [0, -1] inverse SECTION::of_chapter
	   mt_instance_of CompositeRelationship;
	relationship DOCUMENT of_document inverse DOCUMENT::chapters;
	attribute String title;
};

interface SECTION : DOC_CONTENT : persistent {
	relationship List <PARAGRAPH> paragraphs [0, -1] inverse PARAGRAPH::of_section
	   mt_instance_of CompositeRelationship;
	relationship CHAPTER of_chapter inverse CHAPTER::sections;
	attribute String title;
};

interface PARAGRAPH : DOC_CONTENT : persistent {
	attribute String text;
	relationship SECTION of_section inverse SECTION::paragraphs;
	relationship List <DOC_CONTENT> hyperlinks inverse DOC_CONTENT::linked_by;
};

interface DOC_AUTHOR : persistent {
	relationship List <DOCUMENT> documents inverse DOCUMENT::authors;
	attribute String name;
};

Creation of composite objects
You can create composite objects in the same way that you create other regular (non-composite) objects. The following list is an example program which creates a composite document object.

create_a_document is
	local
		doc: DOCUMENT
		author: DOC_AUTHOR
		chap: CHAPTER
		section: SECTION
		paragraph: PARAGRAPH
	do
		!!doc
		current_db.persist(doc)
		doc.set_title("MATISSE-Eiffel Binding")
		!!author.make("Author Foo")
		doc.get_authors.extend(author)

		!!chap.make("1. Introduction")
		doc.get_chapters.extend(chap)

		!!section.make("1.1 Background")
		chap.get_sections.extend(section)
		!!paragraph.make("text here ....")
		section.get_paragraphs.extend(paragraph)

		!!section.make("1.2 Language binding")
		chap.get_sections.extend(section)
		!!paragraph.make("text here ....")
		section.get_paragraphs.extend(paragraph)
		!!paragraph.make("another text here ....")
		section.get_paragraphs.extend(paragraph)

		....
	end

Deletion of composite objects
Since part and the whole of composite object have coincident lifetime, part objects need to be deleted when the whole object is deleted from the database. In the above example, when a document object is deleted, its all chapters, sections and paragraphs are also deleted. When a chapter is deleted, its all sections and paragraphs are deleted while its document to which it belongs is not deleted.
The MATISSE-Eiffel binding does not provide a special routine to delete composite object. You can use the routine ‘mt_remove’ to delete a composite object, which is used to delete a regular (non-composite) object. The routine ‘mt_remove’ detects composite relationships automatically, and call the routine ‘mt_remove’ on all the successor objects through the detected composite relationships if there are any.
The following list is an example using ‘mt_remove’ for a composite object.

delete_a_document is
	local
		entry: MT_ENTRYPOINT
		doc: DOCUMENT
	do
		!!entry.make_from_name("title", "DOCUMENT")
		doc ?= entry.retrieve_first("MATISSE-Eiffel Binding")
		if doc /= Void then
			doc.mt_remove
				-- This removes entire document objects
		end
	end

Locking of composite objects
The binding provides a routine which locks entire composite objects including all part objects. The routine is ‘lock_composite’ which takes an argument to specify the type of lock, read-lock or write-lock. The following list is an example program which write-locks a entire document objects

lock_a_document is
	local
		entry: MT_ENTRYPOINT
		doc: DOCUMENT
	do
		!!entry.make_from_name("title", "DOCUMENT")
		doc ?= entry.retrieve_first("MATISSE-Eiffel Binding")
		if doc /= Void then
			doc.lock_composite(Mtwrite)
				-- This locks entire document objects
		end
	end