How are measures defined?
The Copper measure API is a fluent interface for defining measure calculations asCopperMeasure objects. The code examples on this page use Copper to construct and transform measures.
How are measures organized?
The common layer exposes three constructs for working with measures.IMeasuresConfigurator is the interface on the cube used to register new measures. Call cubeManagerConfigurator.cube(name).measures() to obtain an instance, then use addMeasure() to register a CopperMeasure.
The measure factory pattern allows solutions to define reusable, parameterized measure templates. A factory implements IMeasureFactory<T> where T is an IMeasureFactoryInput describing the inputs. Each factory is identified by a unique plugin key returned by its key() method. A factory registered under the same plugin key for the cube replaces the existing one, which allows overriding the default calculation logic of a built-in measure. For a full reference of all common factory plugin keys, see Measures reference.
ISolutionCube.measures() is the accessor for retrieving a solution’s measure collections programmatically. Use it inside an IModelConfigurer to obtain existing measures and build new ones on top of them.
How to add or modify measures
Via configuration properties
Some measure parameters can be adjusted using configuration properties without writing Java code. For example, confidence levels and display currencies affect how certain measures are computed and displayed. See Configuration properties for supported options.Via the Java API
To add new measures programmatically, build aCopperMeasure and register it via IMeasuresConfigurator in an IModelConfigurer.
The pattern has three elements:
- Obtain an existing measure via
ISolutionCube.measures() - Transform it using the Copper API
- Register it via
IMeasuresConfigurator.addMeasure(name, measure), which names the measure through its first argument
Copper.combine(...) together with the .map(BiConsumer, type) operator: the mapper receives a reader for the combined inputs and a writer for the result. The reader exposes the underlying vector via readVector(int), and the result is written with writer.writeDouble(...). The output literal type is declared with ILiteralType.DOUBLE:
How to register a custom measure factory
Register a custom measure factory by declaring aMeasureFactoryRegistration bean. Spring’s component scanning discovers the bean and registers the factories it wraps. Because the factory is instantiated by Spring, it can depend on other Spring-managed beans:
Map<String, Collection<IMeasureFactory<?>>> keyed by cube name for the latter. Per-cube factories take precedence over globally registered ones. To replace a built-in factory, register the replacement for the cube. See How to override a factory. Multiple factories can be registered in a single MeasureFactoryRegistration bean.
How to rename measures
Measures defined by a solution can be renamed without modifying Java code. Add name overrides toapplication.yml:
For details on defining and customizing measures using the Atoti Configuration API, see the measures reference.