View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.beans;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.IOException;
21  import java.util.Collections;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.Properties;
25  import java.util.Set;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.junit.Test;
30  
31  import static org.junit.Assert.*;
32  
33  /**
34   * @author Guillaume Poirier
35   * @author Juergen Hoeller
36   * @author Chris Beams
37   * @since 08.03.2004
38   */
39  public final class ConcurrentBeanWrapperTests {
40  
41  	private final Log logger = LogFactory.getLog(getClass());
42  
43  	private Set<TestRun> set = Collections.synchronizedSet(new HashSet<TestRun>());
44  
45  	private Throwable ex = null;
46  
47  	@Test
48  	public void testSingleThread() {
49  		for (int i = 0; i < 100; i++) {
50  			performSet();
51  		}
52  	}
53  
54  	@Test
55  	public void testConcurrent() {
56  		for (int i = 0; i < 10; i++) {
57  			TestRun run = new TestRun(this);
58  			set.add(run);
59  			Thread t = new Thread(run);
60  			t.setDaemon(true);
61  			t.start();
62  		}
63  		logger.info("Thread creation over, " + set.size() + " still active.");
64  		synchronized (this) {
65  			while (!set.isEmpty() && ex == null) {
66  				try {
67  					wait();
68  				}
69  				catch (InterruptedException e) {
70  					logger.info(e.toString());
71  				}
72  				logger.info(set.size() + " threads still active.");
73  			}
74  		}
75  		if (ex != null) {
76  			fail(ex.getMessage());
77  		}
78  	}
79  
80  	private static void performSet() {
81  		TestBean bean = new TestBean();
82  
83  		Properties p = (Properties) System.getProperties().clone();
84  
85  		assertTrue("The System properties must not be empty", p.size() != 0);
86  
87  		for (Iterator<?> i = p.entrySet().iterator(); i.hasNext();) {
88  			i.next();
89  			if (Math.random() > 0.9) {
90  				i.remove();
91  			}
92  		}
93  
94  		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
95  		try {
96  			p.store(buffer, null);
97  		}
98  		catch (IOException e) {
99  			// ByteArrayOutputStream does not throw
100 			// any IOException
101 		}
102 		String value = new String(buffer.toByteArray());
103 
104 		BeanWrapperImpl wrapper = new BeanWrapperImpl(bean);
105 		wrapper.setPropertyValue("properties", value);
106 		assertEquals(p, bean.getProperties());
107 	}
108 
109 
110 	private static class TestRun implements Runnable {
111 
112 		private ConcurrentBeanWrapperTests test;
113 
114 		public TestRun(ConcurrentBeanWrapperTests test) {
115 			this.test = test;
116 		}
117 
118 		@Override
119 		public void run() {
120 			try {
121 				for (int i = 0; i < 100; i++) {
122 					performSet();
123 				}
124 			}
125 			catch (Throwable e) {
126 				test.ex = e;
127 			}
128 			finally {
129 				synchronized (test) {
130 					test.set.remove(this);
131 					test.notifyAll();
132 				}
133 			}
134 		}
135 	}
136 
137 
138 	@SuppressWarnings("unused")
139 	private static class TestBean {
140 
141 		private Properties properties;
142 
143 		public Properties getProperties() {
144 			return properties;
145 		}
146 
147 		public void setProperties(Properties properties) {
148 			this.properties = properties;
149 		}
150 	}
151 
152 }