Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Updated README.

  • Loading branch information...
commit 41913d75ba2e3eba36e5e38fe370f1df22888d20 1 parent 15ce673
aroemers authored
Showing with 75 additions and 4 deletions.
  1. +73 −4 README.md
  2. +2 −0  src/gluer/clauses.clj
77 README.md
View
@@ -8,7 +8,7 @@ Gluer is a lightweight framework for injecting objects into other object's field
## Example
-Say we have the following interface and class in one component:
+Let's look at a simple example. Say we have the following interface and class in one component:
```java
public interface Service {
@@ -29,7 +29,7 @@ public class Client {
}
```
-We see here that class `Client` uses some `Service` that is stored in a field. Say we also have the following class in another, separatly developed, component:
+We see here that class `Client` uses some `Service` object that is referenced in a field. Say we also have the following class in another, separatly developed, component:
```java
public class Archiver {
@@ -41,7 +41,7 @@ public class Archiver {
}
```
-The class `Archiver` is a good candidate for being used as a service. So, if want to use an `Archiver` object in a `Client` object, i.e. inject the `Archiver` in its `service` field, we can specify this in file, for instance in `example.gluer`.
+The class `Archiver` is a good candidate for being used as a service. So, if want to use an `Archiver` object in a `Client` object, i.e. inject the `Archiver` in its `service` field, we can specify this in a file, for instance in `example.gluer`, having the following line:
```
associate field Client.service with new Archiver
@@ -69,7 +69,7 @@ public class Archiver2Service implements Service {
Since the `Archiver2Service` is tagged with the `@Adapter` annotation, the Gluer framework recognizes this class and registers it as an available Adapter. Whenever Gluer is requested to inject an `Archiver` (or a subtype of it) object into a field of type `Service` (or a supertype of it), like in our example, it will automatically use above `Archiver2Service` to "adapt" the method calls.
-Gluer has two modes of usage, i.e. a **checking** mode and a **runtime** mode. We can check if our injections will work using Gluer as a *checking* tool. For this we need to write a small configuration file, for instance in `example.config`:
+Gluer has two modes of usage, i.e. a **checking** mode and a **runtime** mode. We can check if our injections will work using Gluer as a *checking* tool. Both modes require a small configuration file, for instance in `example.config`:
```properties
glue: client.gluer
@@ -90,6 +90,10 @@ $ java -cp . -javaagent:gluer.jar=example.config Client
Archiving: something neat
```
+## Building
+
+This project is written in Clojure 1.4. Building it requires [leiningen 2](https://github.com/technomancy/leiningen) to be installed. To build it, clone this repository and type `lein uberjar` in a terminal, while in the root directory of the clone.
+
## Usage
### Adapter classes
@@ -108,12 +112,77 @@ Adapter classes are ordinary classes, that have some simple rules.
### Associations (.gluer files)
+The injections (called associations) are in specified in .gluer files. Each associations takes a _where_ clause, a _what_ clause, and optionally specifies the _adapter_ to use. The lines in the .gluer file take the following form:
+
+```
+associate <where> with <what> [using <adapter>]
+```
+
+The following \<where\> clauses are currently supported :
+
+* `field <class>.<field>`: Means injecting the object into the \<field\> of every instance of the specified \<class\>. An example: `... field somepackage.SomeClass.aField ...`.
+
+The following \<what\> clauses are currently supported:
+
+* `new <class>`: Means injecting a new instance of the specified \<class\> each time the \<where\> clause triggers an injection. The class should have a non-argument constructor. An example: `... new somepackage.SomeClass ...`.
+
+* `single <class>`: Means injecting a single instance of the specified \<class\> each time the \<where\> clause triggers an injection. In other words, the Gluer runtime instantiates the class only once and reuses it for every injection done by this association. The class should have a non-argument constructor. An example: `... single somepackage.SomeClass ...`.
+
+* `call <class>.<method>([argument expressions])`: Means a call to a static (non-void) method each time the \<where\> clause triggers an injection. The returned object is injected. This clause gives more expressive power, in case the former two \<where\> clauses are not sufficient. An example: `... call somepackage.SomeFactory.get(MyConfig.isProduction()) ...`.
+
+Optionally, one can specify which Adapter class should be used when an injection takes place, with `using <adapter>`. The \<adapter\> needs to be a fully qualified name of the Adapter class. Adding this to a association overrules the automatic Adapter resolution as described above. Currently this is the only means to mitigate resolution conflicts.
+
+An example .gluer file:
+
+```
+associate field package.AClass.fieldFoo with new apackage.OtherClass using adapter.OtherClass2Foo
+
+associate field package.AClass.fieldBar with single expensive.InitialisingService
+
+associate field package.Alice.bob with call factories.Persons.create("Eve")
+```
+
### Configuration (.config files)
+To keep the number of required command-line arguments to a minimum and to make a Gluer component easily distributable, a small configuration file is used as a way of communicating the necessary information to the framework. The same configuration file can (and should) be used for both the _checker_ as well as the _runtime_ mode of Gluer.
+
+The format of the configuration is simple. Every line that contains at least one colon (:) is considered a key-value pair. Any subsequent colon after the first one is considered part of the value. All other lines are considered comment and are ignored.
+
+The following keys are currently supported:
+
+* `glue`: The value specifies a .gluer file, relative to the configuration file. This key can be specified multiple times.
+* `verbose`: The value can be either 'true' or 'false'. If set to true, debug logging is displayed.
+* `plug-in`: The value specifies the namespace path to a plug-in file. See the section on 'Extending the framework' below. This key can be specified multiple times.
+* `classpath-entry`: The value specifies a class-path entry, which will be added to the standard classpath automatically. This key can be specified multiple times.
+
+An example .config file:
+
+```properties
+This is just comment text, since it does not contain a colon.
+Empty lines are ignored as well.
+
+glue: path/to/file.gluer
+glue: paths/are/relative/from/the/config.file
+glue: more/colons:are:part/of/the.value
+
+plug-in: gluer.plugin.what-call
+
+classpath-entry: adapters.jar
+
+verbose: false
+```
+
+
+## Extending the framework
+
## Future improvements
+* Make 'glue' paths in the config relative to the configuration file.
+* Checks for overlapping associations
* Generics support
* Plain, adapter-less injections
+* Plug-in system
+* Class-path entries in configuration
## License and disclaimer
2  src/gluer/clauses.clj
View
@@ -89,6 +89,8 @@
;;; The 'call' what clause.
+;;--- TODO: Generalize the call clause? So it supports arbritary statements, like constructors.
+;; Would the type still be statically determinable? Or should we extend the 'new' clause?
(defn- check-expression
[expression]
Please sign in to comment.
Something went wrong with that request. Please try again.