Overview

# NetBeans Architecture Answers for NetBeans Metadata Repository module

- Author: mmatula@netbeans.org
- Answers as of: Dec 7, 2006
- Answers for questions version: 1.24
- Latest available version of questions: 1.26

WARNING: answering questions version 1.24 rather than the current 1.26.

## Interfaces table

##### Group of java interfaces

Interface Name | In/Out | Stability | Specified in What Document?
MDRAPI | Exported | Stable |
OMG-Meta-Object-Facility | Exported | Standard | .../technology/documents/formal/mof.htm
OMG-XML-Metadata-Interchange | Exported | Standard | .../technology/documents/formal/xmi.htm
JSR-40-Java-Metadata-Interface | Exported | Standard | http://java.sun.com/products/jmi
openide | Imported | Official | Lookup, filesystems API, modules API.
MOF-1.4-Metamodel-Definition-XML-file | Imported | Standard | ...//www.omg.org/cgi-bin/doc?ptc/01-10-08
JMI-Reflective-API-and-JMI-interfaces-generated-from-the-MOF-metamodel | Imported | Standard | http://java.sun.com/products/jmi

##### Group of property interfaces

Interface Name | In/Out | Stability | Specified in What Document?
org.netbeans.mdr.persistence.btreeimpl.btreestorage.MDRCache.threshhold | Exported | Private |
storage | Exported | Private |
org.netbeans.mdr.persistence.btreeimpl.uuid | Exported | Private |
org.netbeans.mdr.persistence.btreeimpl.filename | Exported | Private |
org.netbeans.mdr.persistence.memoryimpl.id | Exported | Private |
org.netbeans.mdr.persistence.memoryimpl.fileName | Exported | Private |

##### Group of java.io.File interfaces

Interface Name | In/Out | Stability | Specified in What Document?
Btree-files | Exported | Private | For every storage the b-tree database creates two permanent files - index file (*.btx) and data file (*.btd). When modifying data in the database the b-tree creates an additional backup file (*.btb), which is deleted when the database is shutdown.

## General Information

Question (arch-what): What is this project good for?

Answer: See answer to the use-cases question.

Question (arch-overall): Describe the overall architecture.

Answer: There are two kinds of API classes exposed by MDR:

- The reflective JMI API and JMI interfaces generated for MOF metamodel. These are located in javax.jmi package.
- Proprietary MDRAPI classes exposing additional functionality not standardized by JMI (even notifications mechanism, concept of a repository, JMI mapper, etc.)

By MDR a new kind of API is introduced - JMI interfaces generated from a given metamodel. Since it is expected that the number of NetBeans modules that will use MOF metamodels and JMI API generated from them to manage metadata, it is desirable to establish come conventions for where the generated API should be located (in what packages), where custom implementations of those metamodels should be and some other concepts like naming of metamodels and repositories. Suggested target package for metamodel specific JMI interfaces is org.netbeans.jmi.

Question (arch-usecases): Describe the main use cases of the new API. Who will use it under what circumstances? What kind of code would typically need to be written to use the module?

Answer: The MDR should be used for data-integration accross different modules in the IDE. An example usecase can be found at http://mdr.netbeans.org/example.html. Basic usecases can also be found in the overview of individual API packages in javadoc.

Question (arch-time): What are the time estimates of the work?

Answer: The work is done. MDR was released as part of NB 4.0.

Question (arch-quality): How will the quality of your code be tested and how are future regressions going to be prevented?

Answer: Since MDR is mostly an implementation of JMI standard, it can be tested using the JMI TCK test suite, which includes about 1000 tests for the JMI reflective and metamodel specific API. Besides that we have a set of unit and functional tests testing the proprietary extensions to the JMI standard. Performance regressions can be identified by our performance tests that are also included in our test suite. All of the tests except for the JMI TCK are built using xtest framework and can be run continuously.

Question (arch-where): Where one can find sources for your module?

WARNING: Question with id="arch-where" has not been answered!

## Project and platform dependencies

Question (dep-nb): What other NetBeans projects and modules does this one depend on?

Answer: openide - Lookup, filesystems API, modules API.

Question (dep-non-nb): What other projects outside NetBeans does this one depend on?

Answer: The module depends on output of MOF and JMI specifications. Particularily MOF-1.4-Metamodel-Definition-XML-file and JMI-Reflective-API-and-JMI-interfaces-generated-from-the-MOF-metamodel.

Question (dep-platform): On which platforms does your module run? Does it run in the same way on each?

Answer: There are no known dependencies on any platform. The module is pure Java.

Question (dep-jre): Which version of JRE do you need (1.2, 1.3, 1.4, etc.)?

Answer: The code definitely runs with JRE 1.4 and higher. It has not been tested with earlier JREs. The standalone version of MDR runs on JRE 1.3 and higher.

Question (dep-jrejdk): Do you require the JDK or is the JRE enough?

Answer: JRE is enough.

## Deployment

Question (deploy-jar): Do you deploy just module JAR file(s) or other files as well?

Answer: The module consists of the following jars and autoload modules (jars are listed including the relative path where they have to be placed):

- mdr.jar - main jarfile containing the manifest and layer xml file, integrating MDR with NetBeans
- autoload/mdrapi.jar - autoload module jar containing MDR API
- autoload/jmi.jar - autoload module jar containing JMI reflective API
- autoload/mof.jar - autoload module jar containing JMI API for MOF metamodel
- autoload/jmitoolkit.jar - autoload module jar adding JMI utilities to NB lookup
- autoload/ext/jmiutils.jar - standalone implementation of JMI utilities (XMI reader/writer, JMI mapper, etc.)
- ext/nbmdr.jar - standalone implementation of MDR

Question (deploy-nbm): Can you deploy an NBM via the Update Center?

Answer: Yes.

Question (deploy-shared): Do you need to be installed in the shared location only, or in the user directory only, or can your module be installed anywhere?

Answer: There are no known dependencies on installation location of the module - i.e. one should be able to install the module anywhere.

Question (deploy-packages): Are packages of your module made inaccessible by not declaring them public?

Answer: Yes.

Question (deploy-dependencies): What do other modules need to do to declare a dependency on this one?

Answer: OpenIDE-Module-Module-Dependencies: org.netbeans.api.mdr/1 OpenIDE-Module-Requires: org.netbeans.api.mdr.MDRManager

## Compatibility with environment

Question (compat-i18n): Is your module correctly internationalized?

Answer: Yes.

Question (compat-standards): Does the module implement or define any standards? Is the implementation exact or does it deviate somehow?

Answer: The module implements OMG-Meta-Object-Facility, OMG-XML-Metadata-Interchange and JSR-40-Java-Metadata-Interface.

Question (compat-version): Can your module coexist with earlier and future versions of itself? Can you correctly read all old settings? Will future versions be able to read your current settings? Can you read or politely ignore settings stored by a future version?

Answer: The module itself stores no settings besides the b-tree storage files that are used to store the metadata. B-tree storage files do contain version information. If the module encounters an older version of storage files, the storage is automatically rebooted - i.e. all the stored metadata are lost at that moment. This is fine since MDR serves as a cache for the metadata, not as a primary source of the metadata.

## Access to resources

Question (resources-file): Does your module use `java.io.File` directly?

Answer: B-tree storage implementation works directly with files since it is a standalone database independent from NetBeans and OpenAPI. Btree-files - For every storage the b-tree database creates two permanent files - index file (*.btx) and data file (*.btd). When modifying data in the database the b-tree creates an additional backup file (*.btb), which is deleted when the database is shutdown. In the standalone mode, placement of the DB files can be specified in a system property. When running in NetBeans, the files are located under &nbuserdir/var/cache/mdrstorage directory.

Question (resources-layer): Does your module provide own layer? Does it create any files or folders in it? What it is trying to communicate by that and with which components?

Answer: Yes. It uses layer to register instances into lookup. The module also creates a new folder named MDRepositories, which other modules can use to register their own repositories. The MDR module registers the default repository.

Question (resources-read): Does your module read any resources from layers? For what purpose?

Answer: Yes. The implementation of MDR manager reads list of registered metadata repositories. Currently the registration and discovery of the repositories works using a special dataloader for *.mdr files. So the repository needs to be registered in the layer as a file with "mdr" extension. Properties of the repository are declared as file attributes. This is an obsolete thing which we plan to replace with a different registration mechanism before the release. Here are the changes we envision (any comments are welcome):

- Add setProperties(Map) method to the MDRepository interface - its contract will be that it has to be called once and only once and it has to be called as the first method on a given instance - this method will initialize the repository instance.
- Repositories will be registered in layer as *.instance files. All the properties of a given repository (passed to it in setProperties method as name-value pairs) will be declared as file attributes. An open issue is that it is expected that most modules will want to use (register a new instance of) the default implementation of MDRepository provided by MDR module - NBMDRepositoryImpl class. But this class is not in the API package. Is it a problem?

Question (resources-mask): Does your module mask/hide/override any resources provided by other modules in their layers?

Answer: No.

## Lookup of components

Question (lookup-lookup): Does your module use `org.openide.util.Lookup` or any similar technology to find any components to communicate with? Which ones?

Answer: The lookup is used to find implementation of MDRManager, XMIReader, XMIWriter, JMIMapper and some other less significant interfaces from the api package. The order is important in case of JMIMapper and XMIReader instances, since we have several implementations of those (e.g. a JMIMapper that generates java sources and a JMIMapper that generates class files directly). User is able to choose which one to invoke by changing order of them in the lookup.

Question (lookup-register): Do you register anything into lookup for other code to find?

Answer: It registers instances of the following classes:

- org.netbeans.lib.jmi.xmi.XMIWriterImpl
- org.netbeans.lib.jmi.xmi.WriterFactory
- org.netbeans.lib.jmi.xmi.WriterBase
- org.netbeans.lib.jmi.xmi.Producer
- org.netbeans.lib.jmi.xmi.ProducerFactory
- org.netbeans.lib.jmi.xmi.ReaderFactory
- org.netbeans.lib.jmi.xmi.SAXReader
- org.netbeans.lib.jmi.xmi.Consumer
- org.netbeans.lib.jmi.xmi.ConsumerFactory
- org.netbeans.lib.jmi.xmi.XMISaxReaderImpl
- org.netbeans.lib.jmi.xmi.XmiDtdProducer
- org.netbeans.lib.jmi.mapping.JMIMapperImpl
- org.netbeans.lib.jmi.mapping.JMIMapperCFImpl
- org.netbeans.modules.mdr.MDRManagerImpl

It does it via layer.

Question (lookup-remove): Do you remove entries of other modules from lookup?

Answer: Not really. The module removes only lookup entries added by the standalone jars (nbmdr.jar, jmiutils.jar) it uses to replace them by its own implementation (integrated with NetBeans) of those.

## Execution Environment

Question (exec-property): Is execution of your code influenced by any environment or Java system (`System.getProperty`) property?

Answer: org.netbeans.mdr.persistence.btreeimpl.btreestorage.MDRCache.threshhold It is used in MDRCache to set cache threshhold.

If you go through the source code, you can find more uses of system properties, however those are only effective if the MDR is running as a standalone thing - when running as a module in NetBeans the properties are ignored.

The following properties can be set in the module layer when MDR is running as a module in NetBeans. storage Determines a factory class that is used to create storages. If it is not set, a factory for btree storage is taken defaultly. org.netbeans.mdr.persistence.btreeimpl.uuid Btree storage takes the value as uuid of the storage. org.netbeans.mdr.persistence.btreeimpl.filename Used to set the name of btree storage. It determines names of files used to store data of the storage. org.netbeans.mdr.persistence.memoryimpl.id Used to set uuid of memory storage. org.netbeans.mdr.persistence.memoryimpl.fileName Used to set the name of a file, which is used to store data of memory storage permanently.

Question (exec-component): Is execution of your code influenced by any (string) property of any of your components?

Answer: No.

Question (exec-ant-tasks): Do you define or register any ant tasks that other can use?

WARNING: Question with id="exec-ant-tasks" has not been answered!

Question (exec-classloader): Does your code create its own class loader(s)?

Answer: MDR dynamically generates implementations of JMI interfaces. It defines these classes using its own classloader.

Question (exec-reflection): Does your code use Java Reflection to execute other code?

Answer: Yes - this is used to access metamodel specific API in the implementation of the JMI reflective API.

Question (exec-privateaccess): Are you aware of any other parts of the system calling some of your methods by reflection?

Answer: Implementation of MDR storage is pluggable. MDR creates the right storage factory based on its class name provided in start up properties using reflection. Same holds for pluggable transaction mutex. Custom implementations of collections use java.lang.reflect.Array to implement toArray method. Reflection is used to implement JMI reflective operations in RefStruct and RefEnum interfaces to access implementations of JMI non-reflective features. Bytecode generators use reflection to access features of JMI interfaces.

Question (exec-process): Do you execute an external process from your module? How do you ensure that the result is the same on different platforms? Do you parse output? Do you depend on result code?

Answer: No.

Question (exec-introspection): Does your module use any kind of runtime type information (`instanceof`, work with `java.lang.Class`, etc.)?

Answer: Implementation of JMI objects are expected to be subclasses of MDR handler classes.

Question (exec-threading): What threading models, if any, does your module adhere to?

Answer: The MDR introduces transaction mutex, which ensures atomicity of every operation. Each operation starts a transaction (uses mutex to lock the repository) upon the entrance and ends the transaction (i.e. releases the mutex) when exiting. The default implementation of the mutex supports multiple readers or single writter. The whole MDR is thread safe.

There is one event-dispatching thread created for every repository instance. It takes care of asynchnorous event notifications.

Question (security-policy): Does your functionality require modifications to the standard policy file?

Answer:

No.

Question (security-grant): Does your code grant additional rights to some other code?

Answer:

TBA

## Format of files and protocols

Question (format-types): Which protocols and file formats (if any) does your module read or write on disk, or transmit or receive over the network? Do you generate an ant build script? Can it be edited and modified?

Answer: The module uses files to store metadata. The files are proprietary b-tree database files.

Question (format-dnd): Which protocols (if any) does your code understand during Drag & Drop?

Answer: None - d'n'd is not applicable to MDR - the module has no UI.

Question (format-clipboard): Which data flavors (if any) does your code read from or insert to the clipboard (by access to clipboard on means calling methods on `java.awt.datatransfer.Transferable`?

Answer: None.

## Performance and Scalability

Question (perf-startup): Does your module run any code on startup?

Answer: No. However the first call to MDR made by any of its clients may potentially take a long time, since MDR is initialized lazily. During the first call to it the MDR checks whether the storages are present or whether they need to be rebooted. If everything is OK, the first call takes about a second (caches are populated), otherwise it may take more time necessary for rebooting the storage. Subsequent calls should be fast.

Question (perf-exit): Does your module run any code on exit?

Answer: Shuts down all the repositories (stops event dispatching thread, releases locks on all storage files, flushes caches). Time necessary to perform these operations is not significant.

Question (perf-scale): Which external criteria influence the performance of your program (size of file in editor, number of files in menu, in source directory, etc.) and how well your code scales?

Answer: The module's performance is affected by the amount of data in a single storage file. Usually there is a 1:1 mapping between a repository and a storage file. Although the module does support storage partitioning and federation. Computational complexity of the searches in the default implementation of the storage (b-tree) is logarithmic, so the code should scale. Another thing that influences the performance of the repository is a number of listeners registered on various repository objects.
We should note however that currently there is a know bug in the b-tree storage which causes that complexity of linking objects to a single object in an ordered association is quadratic.

Question (perf-limit): Are there any hard-coded or practical limits in the number or size of elements your code can handle?

Answer: Number of JMI object the MDR can handle is limited by 2^56 and the available disk space. Footprint of a repository containing just the MOF metamodel is about 250KB. After loading metamodel of UML 1.4, which contains about 900 objects and 1700 association links between them it grows to 400KB.

Question (perf-mem): How much memory does your component consume? Estimate with a relation to the number of windows, etc.

Answer: In case of the default storage implementation (b-tree) this is fully configurable by setting the memory cache threshold, b-tree page size, etc. By default the cache size is set to 2048 objects, which should be optimal for typical usage. Explanation of cache size values and their impact on performance can be found in javadoc for MDRCache class.

Question (perf-wakeup): Does any piece of your code wake up periodically and do something even when the system is otherwise idle (no user interaction)?

Answer: No.

Question (perf-progress): Does your module execute any long-running tasks?

Answer: Potentially long running task is a repository boot (may take up to 10 seconds on slow machines - i.e. slower than 800MHz). This is done only once, when the repository is accessed for the first time (in its life, not in a single IDE session) or if the storage files are deleted externaly. When upgrading the higher version of MDR, the storages may be rebooted in case the storage format has changed between the revisions.

Question (perf-huge_dialogs): Does your module contain any dialogs or wizards with a large number of GUI controls such as combo boxes, lists, trees, or text areas?

Answer: No.

Question (perf-menus): Does your module use dynamically updated context menus, or context-sensitive actions with complicated and slow enablement logic?

Answer: No.

Question (perf-spi): How the performance of the plugged in code will be enforced?

Answer: By documenting the sensitive areas.

Built on December 7 2006. | Portions Copyright 1997-2005 Sun Microsystems, Inc. All rights reserved.