1   /*
2    * (C) Copyright 1989-2011 Trend Micro, Inc.
3    * All Rights Reserved.
4    *
5    * This program is an unpublished copyrighted work which is proprietary
6    * to Trend Micro, Inc. and contains confidential information that is not
7    * to be reproduced or disclosed to any other person or entity without
8    * prior written consent from Trend Micro, Inc. in each and every instance.
9    *
10   * WARNING:  Unauthorized reproduction of this program as well as
11   * unauthorized preparation of derivative works based upon the
12   * program or distribution of copies by sale, rental, lease or
13   * lending are violations of federal copyright laws and state trade
14   * secret laws, punishable by civil and criminal penalties.
15   */
16  
17  package com.trendmicro.grid.acl.ds.cache.commands;
18  
19  import com.trendmicro.grid.acl.ds.cache.CacheDestination;
20  import com.trendmicro.grid.acl.ds.cache.CacheSettings;
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import java.util.Collection;
25  import java.util.Map;
26  import java.util.concurrent.Callable;
27  
28  /**
29   * Implements a command that runs the wrapped command in a batch spanning the given cache destinations.
30   *
31   * @author juergen_kellerer, 2011-03-31
32   * @version 1.0
33   */
34  public class BatchCommand<K, V> extends AbstractCommand<K, V> {
35  
36  	private static final Logger log = LoggerFactory.getLogger(BatchCommand.class);
37  
38  	Callable<Map<K, V>> wrappedCommand;
39  	CacheDestination[] cacheDestination;
40  
41  	/**
42  	 * Constructs the command.
43  	 *
44  	 * @param keys			 the keys to remove.
45  	 * @param wrappedCommand   the command to execute in a batch.
46  	 * @param cacheDestination the destination(s) to initiate a batch on.
47  	 */
48  	public BatchCommand(Collection<K> keys, Callable<Map<K, V>> wrappedCommand, CacheDestination... cacheDestination) {
49  		super(keys);
50  		this.wrappedCommand = wrappedCommand;
51  		this.cacheDestination = cacheDestination;
52  	}
53  
54  	/**
55  	 * Calls the wrapped command in a batch and returns the results.
56  	 *
57  	 * @return the results of the wrapped command.
58  	 * @throws Exception the exception thrown by the wrapped command.
59  	 */
60  	protected Map<K, V> callInBatch() throws Exception {
61  		boolean success = false;
62  		boolean[] batchEnabled = new boolean[cacheDestination.length];
63  
64  		final boolean trace = log.isTraceEnabled();
65  		try {
66  			for (int i = 0; i < cacheDestination.length; i++) {
67  				CacheDestination destination = cacheDestination[i];
68  				if (destination.supportsBatching()) {
69  					batchEnabled[i] = destination.startBatch();
70  
71  					if (trace) log.trace("Opened batch on destination {} (success: {})", destination, batchEnabled[i]);
72  				}
73  			}
74  
75  			Map<K, V> result = wrappedCommand.call();
76  			success = true;
77  			return result;
78  
79  		} finally {
80  			for (int i = 0; i < cacheDestination.length; i++) {
81  				try {
82  					if (batchEnabled[i]) {
83  						cacheDestination[i].endBatch(success);
84  
85  						if (trace) log.trace("Closed batch on destination {} (success: {})", cacheDestination[i], success);
86  					}
87  				} catch (Exception e) {
88  					log.warn("TMACL-01730:Failed to close batch on cache destination " + cacheDestination[i], e);
89  				}
90  			}
91  		}
92  	}
93  
94  	/**
95  	 * {@inheritDoc}
96  	 */
97  	@Override
98  	public Map<K, V> call() throws Exception {
99  		if (CacheSettings.NO_BATCHING)
100 			return wrappedCommand.call();
101 		else
102 			return callInBatch();
103 	}
104 }