View Javadoc
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 }