Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2006-2007 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package org.springframework.batch.support.transaction;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 

Factory for transaction aware objects (like lists, sets, maps). If a transaction is active when a method is called on an instance created by the factory, it makes a copy of the target object and carries out all operations on the copy. Only when the transaction commits is the target re-initialised with the copy.

Works well with collections and maps for testing transactional behaviour without needing a database. The base implementation handles lists, sets and maps. Subclasses can implement begin(java.lang.Object) and commit(java.lang.Object,java.lang.Object) to provide support for other resources.

Generally not intended for multi-threaded use, but the append only version of collections gives isolation between threads operating on different keys in a map, provided they only append to the map. (Threads are limited to removing entries that were created in the same transaction.)

Author(s):
Dave Syer
 
 public class TransactionAwareProxyFactory<T> {
 
 	private final T target;
 
 	private final boolean appendOnly;
 
 	private TransactionAwareProxyFactory(T target) {
 		this(targetfalse);
 
 	}
 
 	private TransactionAwareProxyFactory(T targetboolean appendOnly) {
 		super();
 		this. = target;
 		this. = appendOnly;
 	}

Make a copy of the target that can be used inside a transaction to isolate changes from the original. Also called from the factory constructor to isolate the target from the original value passed in.

Parameters:
target the target object (List, Set or Map)
Returns:
an independent copy
 
 	@SuppressWarnings("unchecked")
 	protected synchronized final T begin(T target) {
 		// Unfortunately in Java 5 this method has to synchronized
 		// (works OK without in Java 6).
 		if (target instanceof List) {
 			if () {
 				return (T) new ArrayList();
 			}
 			return (T) new ArrayList((Listtarget);
 		}
 		else if (target instanceof Set) {
			if () {
				return (T) new HashSet();
			}
			return (T) new HashSet((Settarget);
		}
		else if (target instanceof Map) {
			if () {
				return (T) new HashMap();
			}
			return (T) new HashMap((Maptarget);
		}
		else {
			throw new UnsupportedOperationException("Cannot copy target for this type: " + target.getClass());
		}
	}

Take the working copy state and commit it back to the original target. The target then reflects all the changes applied to the copy during a transaction.

Parameters:
copy the working copy.
target the original target of the factory.
	@SuppressWarnings("unchecked")
	protected synchronized void commit(T copy, T target) {
		// Unfortunately in Java 5 this method has to be synchronized
		// (works OK without in Java 6).
		if (target instanceof Collection) {
			if (!) {
				((Collectiontarget).clear();
			}
			((Collectiontarget).addAll((Collectioncopy);
		}
		else {
			if (!) {
				((Maptarget).clear();
			}
			((Maptarget).putAll((Mapcopy);
		}
	}
	private T createInstance() {
		ProxyFactory factory = new ProxyFactory();
		factory.addAdvice(new MethodInterceptor() {
			public Object invoke(MethodInvocation invocationthrows Throwable {
				if (!TransactionSynchronizationManager.isActualTransactionActive()) {
					return invocation.proceed();
				}
cache;
				if (!TransactionSynchronizationManager.hasResource(this)) {
					cache = begin();
					TransactionSynchronizationManager.bindResource(thiscache);
					TransactionSynchronizationManager.registerSynchronization(new TargetSynchronization(thiscache));
				}
				else {
					@SuppressWarnings("unchecked")
retrievedCache = (T) TransactionSynchronizationManager.getResource(this);
					cache = retrievedCache;
				}
				Object result = invocation.getMethod().invoke(cacheinvocation.getArguments());
				if () {
					String methodName = invocation.getMethod().getName();
					if ((result == null && methodName.equals("get"))
							|| (..equals(result) && methodName.startsWith("contains"))) {
						// In appendOnly mode the result of a get might not be
						// in the cache...
						return invocation.proceed();
					}
				}
				return result;
			}
		});
		@SuppressWarnings("unchecked")
instance = (T) factory.getProxy();
		return instance;
	}
	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> createTransactionalMap() {
		return (Map<K, V>) new TransactionAwareProxyFactory(new ConcurrentHashMap<K, V>()).createInstance();
	}
	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> createTransactionalMap(Map<K, V> map) {
		return (Map<K, V>) new TransactionAwareProxyFactory(new ConcurrentHashMap<K, V>(map)).createInstance();
	}
	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> createAppendOnlyTransactionalMap() {
		return (Map<K, V>) new TransactionAwareProxyFactory(new ConcurrentHashMap<K, V>(), true).createInstance();
	}
	@SuppressWarnings("unchecked")
	public static <T> Set<T> createAppendOnlyTransactionalSet() {
	}
	@SuppressWarnings("unchecked")
	public static <T> Set<T> createTransactionalSet() {
	}
	@SuppressWarnings("unchecked")
	public static <T> Set<T> createTransactionalSet(Set<T> set) {
	}
	@SuppressWarnings("unchecked")
	public static <T> List<T> createAppendOnlyTransactionalList() {
	}
	@SuppressWarnings("unchecked")
	public static <T> List<T> createTransactionalList() {
	}
	@SuppressWarnings("unchecked")
	public static <T> List<T> createTransactionalList(List<T> list) {
	}
		private final T cache;
		private final Object key;
		public TargetSynchronization(Object key, T cache) {
			super();
			this. = cache;
			this. = key;
		}
		public void afterCompletion(int status) {
			super.afterCompletion(status);
				synchronized () {
				}
			}
			TransactionSynchronizationManager.unbindResource();
		}
	}
New to GrepCode? Check out our FAQ X