== facets
:idprefix: id_ 


This addon *exports services* for use in other addons. The Facets addon allows for modularization and extension of core
functionality by creating a standard integration point and set of installation/removal APIs.  

=== Dependencies: None

== Setup

This Addon requires the following installation steps.

=== Add configuration to pom.xml 

To use this addon, you must add it as a dependency in the *pom.xml* of your `forge-addon` classified artifact:

[source,xml] 
----
<dependency>
   <groupId>org.jboss.forge.addon</groupId>
   <artifactId>facets</artifactId>
   <classifier>forge-addon</classifier>
   <version>${version}</version>
</dependency>
----      
== Features

Modular functionality::
 Use small building-blocks to compose functionality into higher level constructs. Facets are small pieces of functionality
 that may be accessed individually, or built upon to create decoupled extensions for a known Faceted type. While a circular
 dependency exists in the base type implementations, this ultimately leads to a simplified development experience.
+
[source,java]
----
public class MyFacet extends AbstractFacet<FacetedObject> implements Facet<FacetedObject> {
  @Override
  public boolean install() {
     return true;
  }

  @Override
  public boolean isInstalled() {
     return true;
  }
  
  public void doSomething() {
     // custom functionality for your facet
  }
}
----
+
And the corresponding Faceted type.
+
[source,java]
----
public class FacetedObject extends AbstractFaceted<MyFacet> implements Faceted<MyFacet> {
}
----
+
Once the facet interfaces are implemented, simply add methods and functionality to the facet implementation. This allows
consumers of the facet to use the functionality you have created:
+
[source,java]
----
Faceted<MyFacet> faceted = ...;
MyFacet facet = faceted.getFacet(MyFacet.class);
facet.doSomething();
----

FacetFactory service for simple installation/removal::
 The FacetFactory provides a single API for all Facet operations: both creation of new, detached facet instances, and also
handles the installation of facets directly.
+
[source,java]
----
@Inject
private FacetFactory factory;
...
FacetedObject faceted = new FacetedObject();
MyFacet facet = factory.install(faceted, MyFacet.class);
---- 
+
[TIP] 
====
If your addon uses a container that does not support "@Inject" annotations, services such as the `FacetFactory` may also be 
accessed via the `AddonRegistry`:

----
AddonRegistry registry = ...
Imported<FacetFactory> imported = registry.getServices(FacetFactory.class);
FacetFactory factory = imported.get();
----
==== 


Simple facet prerequisite management::
Since `Facet` implementations are designed for re-use, the projects addon API provides the `@FacetConstraint` annotation, for quickly defining dependencies between facet implementations. The default constraint type is `REQUIRED`.
+
[source,java]
----
@FacetConstraint({OtherFacet.class})
public class MyFacet extends AbstractFacet<FacetedObject> {
   ...
}

@FacetConstraints({
   @FacetConstraint({OtherFacet.class}),
   @FacetConstraint(value={OtherFacet2.class}, type=OPTIONAL)
})
public class MyFacet extends AbstractFacet<FacetedObject> {
   ...
}
----
+
`FacetConstraint` declarations may then be read using the `FacetInspector` utility to inspect annotated types.
+
[source,java]
----
Set<Facet<?>> required = FacetInspector.getRequiredFacets(FacetedObject.class);
----

Consistent programming experience::
 Because the Facet API provides an abstract model for extending functionality of an API, it is used in a number of addons
 and should be considered the standard approach for modular API extension.

Facet Event Support::
 The Facet API will fire FacetEvents when Facets are installed on Faceted objects. 
+
[options="header"]
|===
|Event type |Description

|FacetInstalled
|Fired when a facet is installed in a faceted

|FacetRegistered
|Fired when a facet is registered in a faceted. Facets may be registered when their installation requirements have already been met.

|===
   
You may observe these events by registering a `FacetListener`:

* Classes that implement the `FacetListener` interface are automatically bound to `FacetFactory`;
* In cases where auto-discovery is not possible, `FacetFactory` provides an `addFacetListener(FacetListener)` method for explicit registration.

[source,java]
----
@Inject 
private FacetFactory factory;
...
ListenerRegistration<FacetListener> registration = null;
registration = factory.addFacetListener(new FacetListener(){
	@Override
	public void processEvent(FacetEvent event) {   
		// Do something
	}
});
...
// Remove listener when it is no longer needed
registration.removeListener();
----
* The event is also fired using Furnace's event architecture, so it's possible to listen for events using the add-on container implementation.  

[IMPORTANT] 
====
`Project` objects are invalidated when the pom.xml changes and facets are re-calculated when this happens. For this reason, a FacetListener *MUST*
be idempotent and perform a no-op on repeatable `FacetRegistered` events. 
