private <A extends Action<R>, R extends Result> void maintainCache(A action, R result) {
   if (action instanceof WriteAction) {
     clearCache();
   } else if (action instanceof BatchAction) {
     BatchAction batchAction = (BatchAction) action;
     BatchResult batchRestul = (BatchResult) result;
     for (int i = 0; i < batchAction.getActions().length; i++) {
       // FIXME caste is workaround
       maintainCache((A) batchAction.getActions()[i], (R) batchRestul.getResult(i));
     }
   } else if (action instanceof CachableReadAction) {
     cachedActions.put(action, new CachedResult(result));
   }
 }
 private <A extends Action<R>, R extends Result> R fromCache(A action) {
   if (action instanceof CachableReadAction) {
     CachedResult result = cachedActions.get(action);
     return (R) (result == null ? null : result.getResult());
   } else if (action instanceof BatchAction) {
     BatchAction ba = (BatchAction) action;
     List<Result> results = new ArrayList<Result>(ba.getActions().length);
     for (Action<?> batchAction : ba.getActions()) {
       Result batchResult = fromCache(batchAction);
       if (batchResult == null) {
         return null;
       }
       results.add(batchResult);
     }
     return (R) new BatchResult(results, Collections.EMPTY_LIST);
   }
   return null;
 }