1 package org.apache.maven.plugin.coreit;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.maven.plugin.AbstractMojo;
23 import org.apache.maven.plugin.MojoExecutionException;
24
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.Vector;
33
34 /**
35 * Checks the thread-safe retrieval of components from active component collections.
36 *
37 * @author Benjamin Bentmann
38 * @goal check-thread-safety
39 * @phase validate
40 */
41 public class CheckThreadSafetyMojo
42 extends AbstractMojo
43 {
44
45 /**
46 * Project base directory used for manual path alignment.
47 *
48 * @parameter default-value="${basedir}"
49 * @readonly
50 */
51 private File basedir;
52
53 /**
54 * The available components, as a map.
55 *
56 * @component role="org.apache.maven.plugin.coreit.Component"
57 */
58 private Map componentMap;
59
60 /**
61 * The available components, as a list.
62 *
63 * @component role="org.apache.maven.plugin.coreit.Component"
64 */
65 private List componentList;
66
67 /**
68 * The path to the properties file to create.
69 *
70 * @parameter property="collections.outputFile"
71 */
72 private File outputFile;
73
74 /**
75 * Runs this mojo.
76 *
77 * @throws MojoExecutionException If the output file could not be created.
78 */
79 public void execute()
80 throws MojoExecutionException
81 {
82 Properties componentProperties = new Properties();
83
84 getLog().info( "[MAVEN-CORE-IT-LOG] Testing concurrent component access" );
85
86 ClassLoader pluginRealm = getClass().getClassLoader();
87 ClassLoader coreRealm = MojoExecutionException.class.getClassLoader();
88
89 final Map map = componentMap;
90 final List list = componentList;
91 final List go = new Vector();
92 final List exceptions = new Vector();
93
94 Thread[] threads = new Thread[2];
95 for ( int i = 0; i < threads.length; i++ )
96 {
97 // NOTE: The threads need to use different realms to trigger changes of the collections
98 final ClassLoader cl = ( i % 2 ) == 0 ? pluginRealm : coreRealm;
99 threads[i] = new Thread()
100 {
101 private final ClassLoader tccl = cl;
102
103 public void run()
104 {
105 getLog().info( "[MAVEN-CORE-IT-LOG] Thread " + this + " uses " + tccl );
106 Thread.currentThread().setContextClassLoader( tccl );
107 while ( go.isEmpty() )
108 {
109 // wait for start
110 }
111 for ( int j = 0; j < 10 * 1000; j++ )
112 {
113 try
114 {
115 for ( Object o : map.values() )
116 {
117 o.toString();
118 }
119 for ( Object aList : list )
120 {
121 aList.toString();
122 }
123 }
124 catch ( Exception e )
125 {
126 getLog().warn( "[MAVEN-CORE-IT-LOG] Thread " + this + " encountered concurrency issue", e );
127 exceptions.add( e );
128 }
129 }
130 }
131 };
132 threads[i].start();
133 }
134
135 go.add( null );
136 for ( Thread thread : threads )
137 {
138 try
139 {
140 thread.join();
141 }
142 catch ( InterruptedException e )
143 {
144 getLog().warn( "[MAVEN-CORE-IT-LOG] Interrupted while joining " + thread );
145 }
146 }
147
148 componentProperties.setProperty( "components", Integer.toString( componentList.size() ) );
149 componentProperties.setProperty( "exceptions", Integer.toString( exceptions.size() ) );
150
151 if ( !outputFile.isAbsolute() )
152 {
153 outputFile = new File( basedir, outputFile.getPath() );
154 }
155
156 getLog().info( "[MAVEN-CORE-IT-LOG] Creating output file " + outputFile );
157
158 OutputStream out = null;
159 try
160 {
161 outputFile.getParentFile().mkdirs();
162 out = new FileOutputStream( outputFile );
163 componentProperties.store( out, "MAVEN-CORE-IT-LOG" );
164 }
165 catch ( IOException e )
166 {
167 throw new MojoExecutionException( "Output file could not be created: " + outputFile, e );
168 }
169 finally
170 {
171 if ( out != null )
172 {
173 try
174 {
175 out.close();
176 }
177 catch ( IOException e )
178 {
179 // just ignore
180 }
181 }
182 }
183
184 getLog().info( "[MAVEN-CORE-IT-LOG] Created output file " + outputFile );
185 }
186
187 }