Skip to content

Instantly share code, notes, and snippets.

@hugithordarson
Last active January 7, 2017 00:04
Show Gist options
  • Save hugithordarson/8e00706e5d6d185211e39c1854dc1856 to your computer and use it in GitHub Desktop.
Save hugithordarson/8e00706e5d6d185211e39c1854dc1856 to your computer and use it in GitHub Desktop.
package strimillinn.xperimental;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention( RetentionPolicy.RUNTIME )
public @interface KVCAsync {}
/**
* Stores a list of all keys annotated with @KVCAsync
*/
private List<String> _asyncKeys;
/**
* Stores the calculated values of all _asyncKeys, once they've been calculated.
*/
private Map<String, Object> _asyncValues;
public ProductDetailComponent( WOContext context ) {
super( context );
}
/**
* Checks if the requested key is annotated with @KVCAsync.
* The first time such a method is requested, all keys annotated
* with @KVCAsync are calculated simultaneously and the results then cached.
*/
@Override
public Object valueForKey( String key ) {
if( isAsync( key ) ) {
if( _asyncValues == null ) {
populateAsyncValues();
}
return _asyncValues.get( key );
}
return super.valueForKey( key );
}
/**
* @return A list of names of methods annotated with @KVCAsync
*/
private List<String> asyncKeys() {
if( _asyncKeys == null ) {
_asyncKeys = new ArrayList<>();
for( Method method : getClass().getDeclaredMethods() ) {
if( method.isAnnotationPresent( KVCAsync.class ) ) {
_asyncKeys.add( method.getName() );
}
}
}
return _asyncKeys;
}
/**
* @return true if the given key references a method annotated with @KVCAsync
*/
private boolean isAsync( String key ) {
return asyncKeys().contains( key );
}
/**
* Populates the map of cached asynchronous values
*/
private void populateAsyncValues() {
_asyncValues = Collections.synchronizedMap( new HashMap<>() );
try {
CompletableFuture<?>[] futures = new CompletableFuture[asyncKeys().size()];
int i = 0;
for( String key : asyncKeys() ) {
futures[i++] = CompletableFuture.runAsync( () -> {
_asyncValues.put( key, super.valueForKey( key ) );
} );
}
CompletableFuture.allOf( futures ).get();
}
catch( InterruptedException | ExecutionException e ) {
throw new RuntimeException( "Failed to populate async fields", e );
}
}
@KVCAsync
public BigDecimal basketPenetration() {
return ReportUtil.basketPenetration( selectedObject() ).multiply( new BigDecimal( "100" ) );
}
@KVCAsync
public BigDecimal averageBasketValue() {
return ReportUtil.averageBasketValue( selectedObject() );
}
@KVCAsync
public BigDecimal averageBasketSize() {
return ReportUtil.averageBasketSize( selectedObject() );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment