# Loader  

## User Guide
This is the loader component; it represents the core of the plugin system.  
This README has a more detailed description on the bottom ([Additional Information](#additional-information)).

### Features

- Locate plugins that may be loaded
- Load the plugins that were found
- Control the plugins' life cycles.

### Example Usage

1. To start Renew, execute the following command in the Renew directory:
   1. Under Linux/MacOS:
    `java -p dist:dist/libs -m de.renew.loader gui`
   2. Under Windows:
    `java -p "dist\;dist/libs" -m de.renew.loader gui`
2. Once Renew is running you can use the following command line commands to interact with _Loader_.

### Provided Commands

<!-- Use the classes implementing CLCommand. The 'help' output of the command can be a useful description -->

- `exit [force| ifidle]` - Exits the program
  - `force` - Forces exit
  - `ifidle` - Exits if all plugins are inactive
- `gc` - Triggers the Java garbage collector
- `get [<PluginProperty>| -a | -A]`
  - `<PluginProperty>` - Returns the value of the given PluginProperty
  - `-a` - Returns a listing of all known property names
  - `-A` - Returns a listing of all known property properties
- `info <PluginName>` - Prints all properties of the specified plugin, if it can be found
- `list [-l| --long| -c| --comment| -j|--jar| o]` - Lists all loaded plugins
  - `-l| --long` Prints the list of loaded plugins with more information
  - `-c| --comment` Prints the list of loaded plugins with compile comments
  - `-j| --jar` Prints the list of loaded plugins with all JAR file locations
  - `-o` Prints the list of loaded plugins in an ordered list
- `load <url>` - Loads a plugin from the given URL
  - `h| -h| --h| -help| --help` - Gives examples for usage of 'load' (without `<url>`)
- `script <filename>` - Reads an input file and interprets every line as a PluginManager command
- `set <property>=<value> [<property>=<value> ...]` Globally sets a property to the specified value (Don't use spaces around the "=" sign!)
- `sleep` - Waits for a given time until the next command is executed
- `unload [-v | -r | -m] <PluginName>` - Unloads the plugin with the given name
  - `-v` to see a list of all dependent plug-ins
  - `-r` to unload all dependent plug-ins recursively
  - `-m` to remove given plug-ins iff there are no dependors and at least one further plug-in which provides the same service (EXPERIMENTAL!!!)

A map of recognized commands is stored in the PluginManager. The implementation of the commands is stored in the plugin/command package.

### Installation

Install _Loader_ by putting the JAR file inside the `dist` directory.

It will be automatically loaded at startup of Renew - see below for more configuration options.

Without _Loader_ Renew cannot be started.

### Dependencies

This plugin depends on the following plugins and external libraries:

<!-- must match the `module-info.java` -->

- `log4j`: logging framework
- `JLine`: handles console input
- `Commons CLI`: API for parsing command line options

### Configuration

#### *System variables on startup* 
There are system variables available that control the way plugins are  loaded. These can be set either in the .renew.properties in your home directory or on the command line by using the java "-D" option, as in `java -Dde.renew.plugin.noLoad="Renew Navigator" -p "dist\;dist/libs" -m de.renew.loader gui` (on Windows).
  
The available variables are:  

**NAME**|**DESCRIPTION**  
:-----|:-----|  
`de.renew.plugin.autoload` | Can be set to `false` to only load the plugins specified with `de.renew.plugin.load`.|
`de.renew.plugin.load`| Contains a comma-separated list of plugin names that will be loaded into the system. Plugin names must be given in the way that the loader loads them (e.g. `"Renew JHotDraw"` instead of `CH`).
`de.renew.plugin.noLoad`| Contains a comma-separated list of plugin names that will not be loaded into the system. Consequently, all depending plugins will not be loaded if no other plugin provides the required capability. Plugin names must be given in the way that the loader loads them (e.g. `"Renew JHotDraw"` instead of `CH`).
`pluginLocations` |  Contains a comma-separated list of additional plugin search paths for the plugin manager (use the "\" sign to break up your configuration file into several lines for readability).  
`de.renew.classPath` | Works like the usual Java classpath. Classes found in this Renew classpath are able to access plugins and their services. Classes loaded by the system class loader (using the standard CLASSPATH variable or -classpath option of the Java VM) are                          *not* able to access plugin classes!  
`my.property`|  Change the default value of properties.|

#### Used Properties  
During the initialization of _Loader_, the following properties are used.

(See [Additional Information](#additional-information) for more explanations as referenced in the "Used in" column.)
  
**NAME**|**TYPE**|**DESCRIPTION**|**USED IN**
:-----|:-----:|:-----|-----  
`de.renew.plugin.PluginManager`|`Class`|Starts the loading process.|    
`de.renew.plugin.Loader`|`Class`|Instantiate the class.|  
`de.renew.plugin.locate.PluginLocationFinder`|`Class`|Finds the location of a given Plugin.|Section 1|
`plugin.cfg`|`File`|Since most plugins rely on other plugins' classes to work, it is necessary to load  the plugins in the correct order, first the relayee, then the relayer. This order must be given in this file.|Section 1|                                                                                                  
`de.renew.plugin.locate.PluginSubDirFinder`|`Class`|It is instantiated with an URL. It assumes this to be a File URL, or a Directory URL to be more precise. It will locate all subdirectories of it and look for plugin.cfg files in that directory.|Section 1|
`de.renew.plugin.locate.PluginJarLocationFinder`|`Class`|The `de.renew.plugin.locate.PluginJarLocationFinder` is also created with an URL which it assumes to be a directory. It locates all jar files in that directory and checks if these contain a plugin.cfg file.|Section 1|
`de.renew.plugin.IPlugin`|`Class`|A life cycle management system for the loaded components.|Section 3|
`de.renew.plugin.PluginProperties`|`Class`|Configures plugins in a unified way.|Section 4|

## Developer Guide

### Core Classes

- `Loader`: Tries to find all jars to create a new classpath for Renew and invokes the PluginManagers main method.
- `PluginManager`: This class is the central management facility for providing plugins with access to Renew.
- `PluginLoaderComposition`: This class checks all dependencies and decides when to add which plugin to the PluginManager.

### How to Extend

_Loader_ exposes the following Interfaces.

- `de.renew.plugin.command.CLCommand` - this interface represents commands that can be given to the PluginManager to enable user interaction
- `de.renew.plugin.di.Definition` - this interface allows to provide a service instance
- `de.renew.plugin.di.DependencyFinder` - this interface finds dependencies by a class name
- `de.renew.plugin.di.ServiceContainer` - the PluginManager uses a container to store a ClassLoaderManager, the container itself and PluginManager itself
- `de.renew.plugin.load.ISplashscreenPlugin` - used to resize and move the component which implements this interface
- `de.renew.plugin.load.PluginLoader` - this interface enables to load different types of plugins
- `de.renew.plugin.locate.PluginLocationFinder` - this interface abstracts the process of looking for plugins (in the file system, remote)
- `de.renew.plugin.ClassLoaderManager` - the PluginManager uses a classloader manager to get a system dependent classloader
- `de.renew.plugin.CommandsListener` - removes and adds commands
- `de.renew.plugin.CommandsProvider` -  an observable that provides information about the adding and removing of `ClCommands`
- `de.renew.plugin.IPlugin` - this is the interface that all active Plugins (i.e., the mainClass attribute in the plugin.cfg) must implement
- `de.renew.plugin.IPluginManagerListener` - callback interface for events that are generated by the Pluginmanager
- `de.renew.plugin.LogStrategy` - a Log strategy used by the PluginManager to use several ways of configuring the logging mechanism
- `de.renew.plugin.SoftDependency` -  instances of this class are informed a `SoftDependency` instance about changes in the availability of a certain plugin service

### Additional Information

<!-- Common issues, explanations for inconsistencies, etc. -->

These are additional explanations which are also referenced in "Used Properties".

#### 1. Locating plugins  
The PluginManager will need to look for plugins that can be loaded.  
The Java interface used for this is `de.renew.plugin.locate.PluginLocationFinder`.  
It provides a method `findPluginLocations()` that returns a Collection of `PluginProperties`; each one of these properties will contain the information necessary to create one plugin.  
  
The actual implementor of this interface used by the PluginManager is the `de.renew.plugin.locate.PluginLocationFinders` class, a Composition class of `PluginLocationFinder` objects with a Singleton access interface (so only one instance is present in the system).  
Other `PluginLocationFinder` instances can be added to this Singleton by `add/removeLocationFinder` methods.
The PluginManager itself adds instances of two classes to the Composition:  
- `de.renew.plugin.locate.PluginSubDirFinder` objects and  
- `de.renew.plugin.locate.PluginJarLocationFinder` objects.  
Both are configured with the same start URL to look for plugins:  
- the plugins/ directory beneath the directory of the location where the `PluginManager` was loaded from (i.e., usually the loader.jar). If that cannot be determined, the present directory will be used.  
- any configured `pluginLocations_<i> property`, where \<i> is an integer number, 0 and larger.  
  
##### 1.1 PluginSubDirFinder search strategy  
The `de.renew.plugin.locate.PluginSubDirFinder` is instantiated with an URL.  
It assumes this to be a File URL, or a Directory URL to be more precise.  
It will locate all subdirectories of it and look for plugin.cfg files in these directories.  
If one is found, it is used to create a result `PluginProperties` object.  
The containing directory will be the URL assumed to contain the class code for the plugin.  
  
##### 1.2 PluginJarLocationFinder search strategy  
The `de.renew.plugin.locate.PluginJarLocationFinder` is also created with an URL which it assumes to be a directory.  
It locates all jar files in that directory and checks if these contain a plugin.cfg file.  
These are used to construct the `PluginProperties` objects, with its URL property set to the jar file URL.  
  
#### 2. Loading plugins 
After the `PluginProperties` objects have been created, they are used to construct instances of the plugins they refer to.  
This is done by delegating the loading to the `de.renew.plugin.load.PluginLoaderComposition`, a composition object to and from which implementors of the `PluginLoader` interface can be added and removed.  
These loaders will, for each `PluginProperties` object,  
- add the plugin byte code to the class loader  
- create an `IPlugin` object if applicable.  
Because they instantiate the main class of the plugin, it depends on them to decide how to do this, especially which constructor is called.  
  
In the present setup, only one loader class is available, the `SimplePluginLoader.`  
It uses reflection to invoke a constructor with the given `PluginProperties` as an argument,  creating a `IPlugin` object.  
This facilitates the use of the `de.renew.plugin.PluginAdapter` class.  
  
Since most plugins rely on other plugins' classes to work, it is necessary to load the plugins in the correct order: first the relied upon one, then the reliant one .  
This order must be given by the plugin's developer in the `plugin.cfg` file.  
It uses the notion of "services" to designate which other components are needed.  
Each plugin defines a list of services it provides, each service a string solely used to tell it apart from other services so it can be rather freely chosen; only name conflicts need to be prevented; most of the time, the name of the most important package within the component will work.  
These provisions are listed, comma-separated, in the "provides" property.  
On the other hand, a list of services required to start this component must be given in the "requires" property.  
As an example, the "Console" component provides `de.renew.prompt` and requires `de.renew.util`and `ch.ifa.draw`.   
Its `plugin.cfg` file therefore contains the lines  
provides = `de.renew.prompt`  
requires = `de.renew.util`, `ch.ifa.draw`
  
If all dependencies are declared correctly, the order of dependencies will be established by the plugin system and used to load the components.  
Be aware that circular dependencies are NOT allowed!
  
#### 3. Plugin life cycle  
Analogous to the Java constructor, the plugin system uses a life cycle management system for the loaded components.  
The methods used for this are declared in `de.renew.plugin.IPlugin` and are called `init()` and `cleanup()`.  
The `init()` method is used to notify the plugin object that it has been loaded into the system.  
At that time, the dependencies of this plugin are guaranteed to be fulfilled; this may not be the case when the constructor is called!  
The `cleanup()` method notifies the plugin that it is being unloaded and should free any resources it locks, unregister menu entries it provides etc.  
Note that calling `cleanup()` and removing this plugin from the dependency list are the only action the plugin system takes when unloading a plugin;  it does not remove the provided classes from the class loader.  

#### 4. Plugin configuration  
To configure plugins in a unified way, the `de.renew.plugin.PluginProperties` class is provided.  
It is a subclass of the `java.util.Properties` class and provides the following benefits:  
- It contains `getProperty` methods for boolean and int property values, parsing the String property to create a correctly typed result.
- The boolean get will return false ONLY if the property contains the string "false". The rationale behind this is to reflect the fact that the property is set at all.  
- The user has two different possibilities to change the default value of properties (which should be given by the plugin developer in the plugin.cfg file):  
  1. by setting the property in the `.renew.properties` file in her home directory or in the installation directory (config/renew.properties).  
     (e.g. my.property = false)  
  2. by setting a system property via the command line  
     (e.g. in the startup Java call: java -Dmy.property=false -jar loader.jar)  
  
When a developer creates the plugin's original `plugin.cfg` file, he must include all properties used throughout the plugin, along with their default values. The `plugin.cfg` file is used to determine the set of "known" properties of the plugin  at runtime. If a property should not be set by default, the special keyword  &lt;not set> can be used for the property's value (this works only with `plugin.cfg`, not with any of the other configuration possibilities available to the user!)  

#### 5. Commands  
To be able to interact with the user, the plugin system defines the Java interface `de.renew.plugin.command.CLCommand` (for command line command).  
These follow the Command design pattern and provide a method execute which takes a String array as arguments.  
It is possible for plugins to add additional commands provided by the plugin by notifying the `PluginManager` via its `addCLCommand` method;  to remove a command, an analogous `removeCLCommand` is available.  
Every command is identified by a name given in the `addCLCommand` call.  
If two commands of the same name are added, the second one will overwrite the first one.  
`CLCommand` also defines a `getDescription` which should return a String that describes the functionality of the command to the user.  
  
`CLCommand` implementations are advised to provide feedback to the user neither by using `System.out` nor through the Logging API.  Instead they  should use the `PrintWriter` stream given to the execute method.  

#### 6. Logging  
The first action of the Loader class is to load non-plugin libraries such as `log4j` and configure the logging framework. The configuration of the logging framework is done through separate configuration files, please read the Renew user's guide for details.  
  
All plugins are advised to use the `log4j` framework instead of System.out  messages.  There are different log levels available, namely:    
- ERROR   - Information about severe problems that prevent operation.  
- WARN    - Minor problems (that may indicate misconfiguration).  
- INFO    - Output intended for users during normal operation.  
- DEBUG   - Debug output, for users and developers.  
  
Simulation step trace logging should go to the INFO level to the simulation-specific logger instance (see the "Renew Simulator" plug-in).