Last active
January 7, 2017 00:04
-
-
Save hugithordarson/8e00706e5d6d185211e39c1854dc1856 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package strimillinn.xperimental; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
@Retention( RetentionPolicy.RUNTIME ) | |
public @interface KVCAsync {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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