Architecture
Contents
Overview
Freeplane is a Java Swing application that has two major variants:
- Standalone desktop application (full functionality)
- This is the application most people know.
- The distribution contains also a Portable version of the desktop application. It's just a different style of packaging the application to make it portable on USB sticks etc. but it's not another application.
- Browser applet (limited functionality)
- Collaboration features (as in FreeMind) are not yet available.
Projects
All major components have their own project (toplevel directory in the version control system and an Eclipse project) and they are build into separate JARs.
freeplane freeplane_mac freeplane_plugin_bugreport freeplane_plugin_help freeplane_plugin_latex freeplane_plugin_script freeplane_plugin_script_test freeplane_plugin_svg
Their build is described in build.xml files:
$ grep -H /freeplane.*jar freeplane/ant/ant.properties; \ egrep '(<jar )|property.*name="free.*jar"' */ant/build.xml freeplane/ant/ant.properties: freeplaneviewer.jar = ${freeplane.dist.lib}/freeplaneviewer.jar freeplane/ant/ant.properties: freeplaneeditor.jar = ${freeplane.dist.lib}/freeplaneeditor.jar freeplane/ant/ant.properties: freeplaneosgi.jar = ${freeplane.dist.lib}/freeplaneosgi.jar freeplane/ant/ant.properties: freeplanemac.jar = ${freeplane.ext.lib}/freeplanemac.jar freeplane/ant/build.xml: <property name="freeplaneant.jar" value="${workspace}/freeplane_framework/ant/lib/freeplaneant.jar" /> freeplane/ant/build.xml: <property name="freeplaneplugin.jar" value="${dist.osgi.dir}/org.freeplane.core.jar" /> freeplane/ant/build.xml: <jar jarfile="${freeplaneviewer.jar}"> freeplane/ant/build.xml: <jar jarfile="${freeplaneeditor.jar}" manifest="${manifest}"> freeplane/ant/build.xml: <jar jarfile="${freeplaneosgi.jar}"> freeplane/ant/build.xml: <jar jarfile="${freeplaneplugin.jar}"> freeplane_mac/ant/build.xml: <jar jarfile="${workspace}/freeplane/lib/freeplanemac.jar" update="false" > freeplane_plugin_bugreport/ant/build.xml: <property name="freeplaneplugin.jar" value="${dist}/org.freeplane.plugin.bugreport.jar"/> freeplane_plugin_bugreport/ant/build.xml: <jar jarfile="${freeplaneplugin.jar}"> freeplane_plugin_help/ant/build.xml: <property name="freeplaneplugin.jar" value="${dist}/org.freeplane.plugin.help.jar"/> freeplane_plugin_help/ant/build.xml: <jar jarfile="${freeplaneplugin.jar}"> freeplane_plugin_latex/ant/build.xml: <property name="freeplaneplugin.jar" value="${dist}/org.freeplane.plugin.latex.jar"/> freeplane_plugin_latex/ant/build.xml: <jar jarfile="${freeplaneplugin.jar}"> freeplane_plugin_script/ant/build.xml: <property name="freeplaneplugin.jar" value="${dist}/org.freeplane.plugin.script.jar"/> freeplane_plugin_script/ant/build.xml: <jar jarfile="${freeplaneplugin.jar}"> freeplane_plugin_svg/ant/build.xml: <property name="freeplaneplugin.jar" value="${dist}/org.freeplane.plugin.svg.jar"/> freeplane_plugin_svg/ant/build.xml: <jar jarfile="${freeplaneplugin.jar}">
The additional projects, freeplane_devresources and freeplane_framework, have a higher level scope; the latter is the centralized entry into the build system to build the whole application:
$ cd freeplane_framework/ant $ ant build dist
OSGI Framework
The architecture is based on the OSGI framework and uses Knoplerfish as OSGI implementation.
The fact that Freeplane is build on OSGI has the following consequences:
- All of Freeplane's components are packaged as OSGI bundles (aka "plugins").
- Freeplane is launched in two steps:
- The OSGI kernel, which is an external library, is launched.
- The kernel initiates loading of all plugins.
Plugins
All Freeplane projects but freeplane build a single plugin.jar (freeplane builds one plugin consisting of four JARs):
$ cd "/Program Files/Freeplane" $ find . -name [pf][rl]\*.jar -o -name \*.MF core/org.freeplane.core/lib/freeplaneeditor.jar core/org.freeplane.core/lib/freeplanemac.jar core/org.freeplane.core/lib/freeplaneosgi.jar core/org.freeplane.core/lib/freeplaneviewer.jar core/org.freeplane.core/META-INF/MANIFEST.MF framework.jar plugins/org.freeplane.plugin.bugreport/lib/plugin.jar plugins/org.freeplane.plugin.bugreport/META-INF/MANIFEST.MF plugins/org.freeplane.plugin.latex/lib/plugin.jar plugins/org.freeplane.plugin.latex/META-INF/MANIFEST.MF plugins/org.freeplane.plugin.script/lib/plugin.jar plugins/org.freeplane.plugin.script/META-INF/MANIFEST.MF plugins/org.freeplane.plugin.svg/lib/plugin.jar plugins/org.freeplane.plugin.svg/META-INF/MANIFEST.MF
Structure of a plugin
A plugin is defined by its MANIFEST.MF, here an extract from the org.freeplane.core plugin (core/org.freeplane.core/META-INF/MANIFEST.MF):
Bundle-Name: org.freeplane.core Bundle-Version: 1.0.1 Bundle-ClassPath: lib/freeplaneviewer.jar, lib/freeplaneeditor.jar, lib/freeplanemac.jar, lib/freeplaneosgi.jar, lib/commons-lang-2.0.jar, lib/forms-1.0.5.jar, lib/gnu-regexp-1.1.4.jar, lib/SimplyHTML.jar, lib/jortho.jar Bundle-Activator: org.freeplane.main.osgi.Activator Import-Package: org.osgi.framework Export-Package: org.apache.commons.lang, org.freeplane.core.addins, org.freeplane.core.controller, [...] org.freeplane.view.swing.ui.mindmapmode
This defines the class path that is available within the bundle (Bundle-ClassPath), its version (versioning support is an important feature of OSGI), the list of packages that this plugin exports to others (Export-Package) and the Activator class of the bundle (Bundle-Activator).
Startup sequence
The startup sequence begins with essentially the following command (compare freemind.sh):
cd "/Program Files/Freeplane" java \ -jar ./framework.jar" \ -xargs ./init.xargs"
(The remaining arguments are mainly used for Knoplerfish configuration and memory settings.) The JAR is the Knoplerfish implementation JAR and init.xargs contains the directory where the plugin lookup should start:
$ cat init.xargs -istart org.freeplane.core
This tells Knoplerfish to load the org.freeplane.core plugin first. Knoplerfish inspects core/org.freeplane.core/META-INF/MANIFEST.MF for the Activator class of this bundle. As we have seen in #Structure of a plugin the Activator class is org.freeplane.main.osgi.Activator.
Knoplerfish then runs org.freeplane.main.osgi.Activator.start() which then performs all the remaining startup steps:
- It creates an instance of org.freeplane.main.application.Freeplane which is responsible for the creation of controllers, actions, menus - short the complete basic application.
- Then it loads the other plugins from directory plugins, one after the other, by creating them from by loading their JARs and starting them (see ActivatorImpl.loadPlugins())
// org.freeplane.main.osgi.ActivatorImpl.startFramework() starter = new FreeplaneStarter(); loadPlugins(context); final Controller controller = starter.createController();
OSGI support in Eclipse
Like Freeplane, Eclipse is based on an OSGI kernel. For this reason Eclipse provides very good support for developing OSGI applications:
- All Bundle properties can be managed via the project properties.
- Launch configurations don't need to rely on Knopflerfish. - One launch configuration in the Freeplane sources, freeplane_devresources/eclipse/freeplane-osgi.launch, uses Eclipse' standard OSGI implementation.
Note: Unlike in the "real application" it's necessary to list all plugins to load in the launch configuration. In the regularly deployed application all plugins in the plugin subdirectory are loaded. (By the way also the user's Freeplane directory is scanned for plugins in a plugin directory if this exists.)
Architectural concepts
Freeplane's Architecture has some special basic elements which are used for structuring and organizing code:
- Plugins (OSGI bundles), the most basic ones, have been mentioned already.
- Features/Extensions
Plugins
The simplest plugin just needs a single class, the Activator class. If it should do some work then it should define an action, hooks them into the menu. So most of the work of creating a plugin will be spent setting up the directory/project structure.
Plan (VB): add a freeplane_ant task that creates a new plugin skeleton.
Modes
- MindMapMode
- BrowserMode
- FileMode
Mde Controller
Set of actions available for the user
TODO
Features/Extensions
TODO: Feature or Extension?
Features implement a bit of functionality like an icon assigned to a node, a note, an attribute, etc. A feature ideally consists of up to four parts, as in org.freeplane.features.common.edge:
- a contribution to the map model; it holds the actual data, like a text, a color etc. (EdgeModel),
- a controller class that integrates the feature into the application by registering actions and listeners (EdgeController),
- a view which displays the element in a map; it is often implemented in a separate java package e.g.org.freeplane.view.swing.map.edge,
- and a builder class that is able to serialize and de-serialize the model into XML, i.e. to store the model within the map (EdgeBuilder),
TODO: add more details! Is EdgeStyle a fourth, general part?
Architectural principles
TODO: put the general guidelines here