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  import org.apache.maven.plugin.MojoFailureException;
25  
26  import java.io.File;
27  import java.io.FileOutputStream;
28  import java.io.IOException;
29  import java.io.OutputStream;
30  import java.util.Iterator;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Properties;
34  import java.util.Vector;
35  
36  /**
37   * Checks the thread-safe retrieval of components from active component collections.
38   * 
39   * @goal check-thread-safety
40   * @phase validate
41   * 
42   * @author Benjamin Bentmann
43   */
44  public class CheckThreadSafetyMojo
45      extends AbstractMojo
46  {
47  
48      /**
49       * Project base directory used for manual path alignment.
50       * 
51       * @parameter default-value="${basedir}"
52       * @readonly
53       */
54      private File basedir;
55  
56      /**
57       * The available components, as a map.
58       * 
59       * @component role="org.apache.maven.plugin.coreit.Component"
60       */
61      private Map componentMap;
62  
63      /**
64       * The available components, as a list.
65       * 
66       * @component role="org.apache.maven.plugin.coreit.Component"
67       */
68      private List componentList;
69  
70      /**
71       * The path to the properties file to create.
72       * 
73       * @parameter expression="${collections.outputFile}"
74       */
75      private File outputFile;
76  
77      /**
78       * Runs this mojo.
79       * 
80       * @throws MojoFailureException If the output file could not be created.
81       */
82      public void execute()
83          throws MojoExecutionException
84      {
85          Properties componentProperties = new Properties();
86  
87          getLog().info( "[MAVEN-CORE-IT-LOG] Testing concurrent component access" );
88  
89          ClassLoader pluginRealm = getClass().getClassLoader();
90          ClassLoader coreRealm = MojoExecutionException.class.getClassLoader();
91  
92          final Map map = componentMap;
93          final List list = componentList;
94          final List go = new Vector();
95          final List exceptions = new Vector();
96  
97          Thread[] threads = new Thread[2];
98          for ( int i = 0; i < threads.length; i++ )
99          {
100             // NOTE: The threads need to use different realms to trigger changes of the collections
101             final ClassLoader cl = ( i % 2 ) == 0 ? pluginRealm : coreRealm;
102             threads[i] = new Thread()
103             {
104                 private final ClassLoader tccl = cl;
105 
106                 public void run()
107                 {
108                     getLog().info( "[MAVEN-CORE-IT-LOG] Thread " + this + " uses " + tccl );
109                     Thread.currentThread().setContextClassLoader( tccl );
110                     while ( go.isEmpty() )
111                     {
112                         // wait for start
113                     }
114                     for ( int j = 0; j < 10000; j++ )
115                     {
116                         try
117                         {
118                             for ( Iterator it = map.values().iterator(); it.hasNext(); )
119                             {
120                                 it.next().toString();
121                             }
122                             for ( Iterator it = list.iterator(); it.hasNext(); )
123                             {
124                                 it.next().toString();
125                             }
126                         }
127                         catch ( Exception e )
128                         {
129                             getLog().warn( "[MAVEN-CORE-IT-LOG] Thread " + this + " encountered concurrency issue", e );
130                             exceptions.add( e );
131                         }
132                     }
133                 }
134             };
135             threads[i].start();
136         }
137 
138         go.add( null );
139         for ( int i = 0; i < threads.length; i++ )
140         {
141             try
142             {
143                 threads[i].join();
144             }
145             catch ( InterruptedException e )
146             {
147                 getLog().warn( "[MAVEN-CORE-IT-LOG] Interrupted while joining " + threads[i] );
148             }
149         }
150 
151         componentProperties.setProperty( "components", Integer.toString( componentList.size() ) );
152         componentProperties.setProperty( "exceptions", Integer.toString( exceptions.size() ) );
153 
154         if ( !outputFile.isAbsolute() )
155         {
156             outputFile = new File( basedir, outputFile.getPath() );
157         }
158 
159         getLog().info( "[MAVEN-CORE-IT-LOG] Creating output file " + outputFile );
160 
161         OutputStream out = null;
162         try
163         {
164             outputFile.getParentFile().mkdirs();
165             out = new FileOutputStream( outputFile );
166             componentProperties.store( out, "MAVEN-CORE-IT-LOG" );
167         }
168         catch ( IOException e )
169         {
170             throw new MojoExecutionException( "Output file could not be created: " + outputFile, e );
171         }
172         finally
173         {
174             if ( out != null )
175             {
176                 try
177                 {
178                     out.close();
179                 }
180                 catch ( IOException e )
181                 {
182                     // just ignore
183                 }
184             }
185         }
186 
187         getLog().info( "[MAVEN-CORE-IT-LOG] Created output file " + outputFile );
188     }
189 
190 }