1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.apache.maven.plugin.eclipse.writers;
15
16 import java.io.File;
17 import java.io.FileInputStream;
18 import java.io.FileOutputStream;
19 import java.io.IOException;
20 import java.util.Arrays;
21 import java.util.HashSet;
22 import java.util.Iterator;
23 import java.util.Set;
24 import java.util.jar.Attributes;
25 import java.util.jar.Manifest;
26
27 import org.apache.maven.artifact.repository.ArtifactRepository;
28 import org.apache.maven.plugin.MojoExecutionException;
29 import org.apache.maven.plugin.eclipse.Constants;
30 import org.apache.maven.plugin.eclipse.EclipseSourceDir;
31 import org.apache.maven.plugin.eclipse.Messages;
32 import org.apache.maven.plugin.eclipse.writers.wtp.AbstractWtpResourceWriter;
33 import org.apache.maven.plugin.ide.IdeDependency;
34 import org.apache.maven.plugin.ide.IdeUtils;
35 import org.apache.maven.plugin.ide.JeeUtils;
36 import org.apache.maven.plugin.logging.Log;
37 import org.apache.maven.project.MavenProject;
38
39
40
41
42
43
44
45
46
47 public class EclipseManifestWriter
48 extends AbstractEclipseWriter
49 {
50
51 private static final String MANIFEST_MF_FILENAME = "MANIFEST.MF";
52
53 private static final String META_INF_DIRECTORY = "META-INF";
54
55 private static final String GENERATED_RESOURCE_DIRNAME =
56 "target" + File.separatorChar + "generated-resources" + File.separatorChar + "eclipse";
57
58 private static final String WEBAPP_RESOURCE_DIR =
59 "src" + File.separatorChar + "main" + File.separatorChar + "webapp";
60
61
62
63
64
65
66
67
68
69 private static String getWebContentBaseDirectory( EclipseWriterConfig config )
70 throws MojoExecutionException
71 {
72
73 File warSourceDirectory =
74 new File( IdeUtils.getPluginSetting( config.getProject(), JeeUtils.ARTIFACT_MAVEN_WAR_PLUGIN,
75 "warSourceDirectory", WEBAPP_RESOURCE_DIR ) );
76
77 String webContentDir =
78 IdeUtils.toRelativeAndFixSeparator( config.getEclipseProjectDirectory(), warSourceDirectory, false );
79
80
81 String result = config.getProject().getBasedir().getAbsolutePath() + File.separatorChar + webContentDir;
82
83 return result;
84 }
85
86
87
88
89
90
91
92 public String getMetaInfBaseDirectory( MavenProject project )
93 throws MojoExecutionException
94 {
95 String metaInfBaseDirectory = null;
96
97 if ( this.config.getProject().getPackaging().equals( Constants.PROJECT_PACKAGING_WAR ) )
98 {
99
100
101 metaInfBaseDirectory = getWebContentBaseDirectory( this.config );
102
103 this.log.debug( "Attempting to use: " + metaInfBaseDirectory + " for location of META-INF in war project." );
104
105 File metaInfDirectoryFile =
106 new File( metaInfBaseDirectory + File.separatorChar + EclipseManifestWriter.META_INF_DIRECTORY );
107
108 if ( !metaInfDirectoryFile.exists()
109 || ( metaInfDirectoryFile.exists() && !metaInfDirectoryFile.isDirectory() ) )
110 {
111 metaInfBaseDirectory = null;
112 }
113 }
114
115 for ( int index = this.config.getSourceDirs().length - 1; metaInfBaseDirectory == null && index >= 0; index-- )
116 {
117
118 File manifestFile =
119 new File( this.config.getEclipseProjectDirectory(), this.config.getSourceDirs()[index].getPath()
120 + File.separatorChar + EclipseManifestWriter.META_INF_DIRECTORY + File.separatorChar
121 + EclipseManifestWriter.MANIFEST_MF_FILENAME );
122
123 this.log.debug( "Checking for existence of META-INF/MANIFEST.MF file: " + manifestFile );
124
125 if ( manifestFile.exists() )
126 {
127 metaInfBaseDirectory = manifestFile.getParentFile().getParent();
128 }
129 }
130
131 return metaInfBaseDirectory;
132 }
133
134
135
136
137
138
139
140
141
142
143
144 public void write()
145 throws MojoExecutionException
146 {
147 File manifestFile = null;
148 if ( config.getManifestFile() == null )
149 {
150
151 String metaInfBaseDirectory = getMetaInfBaseDirectory( this.config.getProject() );
152
153 if ( metaInfBaseDirectory == null )
154 {
155
156 throw new MojoExecutionException(
157 Messages.getString(
158 "EclipseCleanMojo.nofilefound",
159 new Object[] { EclipseManifestWriter.META_INF_DIRECTORY } ) );
160 }
161 manifestFile =
162 new File( metaInfBaseDirectory + File.separatorChar + EclipseManifestWriter.META_INF_DIRECTORY
163 + File.separatorChar + EclipseManifestWriter.MANIFEST_MF_FILENAME );
164
165 }
166 else
167 {
168 manifestFile = config.getManifestFile();
169 }
170
171 Manifest manifest = createNewManifest();
172
173 log.info( "MANIFEST LOCATION: " + manifestFile );
174
175 if ( shouldNewManifestFileBeWritten( manifest, manifestFile ) )
176 {
177 log.info( "Writing manifest..." );
178
179 manifestFile.getParentFile().mkdirs();
180
181 try
182 {
183 FileOutputStream stream = new FileOutputStream( manifestFile );
184
185 manifest.write( stream );
186
187 stream.close();
188
189 }
190 catch ( Exception e )
191 {
192 this.log.error( Messages.getString( "EclipsePlugin.cantwritetofile",
193 new Object[] { manifestFile.getAbsolutePath() } ) );
194 }
195 }
196 }
197
198
199
200
201
202
203
204 public static void addManifestResource( Log log, EclipseWriterConfig config )
205 throws MojoExecutionException
206 {
207
208 EclipseManifestWriter manifestWriter = new EclipseManifestWriter();
209 manifestWriter.init( log, config );
210
211 String packaging = config.getProject().getPackaging();
212
213 String manifestDirectory = manifestWriter.getMetaInfBaseDirectory( config.getProject() );
214
215 if ( !Constants.PROJECT_PACKAGING_EAR.equals( packaging )
216 && !Constants.PROJECT_PACKAGING_WAR.equals( packaging ) && manifestDirectory == null )
217 {
218
219 String generatedResourceDir =
220 config.getProject().getBasedir().getAbsolutePath() + File.separatorChar
221 + EclipseManifestWriter.GENERATED_RESOURCE_DIRNAME;
222
223 manifestDirectory = generatedResourceDir + File.separatorChar + "META-INF";
224
225 try
226 {
227 new File( manifestDirectory ).mkdirs();
228 File manifestFile = new File( manifestDirectory + File.separatorChar + "MANIFEST.MF" );
229 if ( manifestFile.exists() )
230 {
231 manifestFile.delete();
232 }
233 manifestFile.createNewFile();
234 }
235 catch ( IOException e )
236 {
237 log.error( Messages.getString( "EclipsePlugin.cantwritetofile", new Object[] { manifestDirectory
238 + File.separatorChar + "META-INF" + File.separatorChar + "MANIFEST.MF" } ) );
239 }
240
241 log.debug( "Adding " + EclipseManifestWriter.GENERATED_RESOURCE_DIRNAME + " to eclipse sources " );
242
243 EclipseSourceDir[] sourceDirs = config.getSourceDirs();
244 EclipseSourceDir[] newSourceDirs = new EclipseSourceDir[sourceDirs.length + 1];
245 System.arraycopy( sourceDirs, 0, newSourceDirs, 0, sourceDirs.length );
246 newSourceDirs[sourceDirs.length] =
247 new EclipseSourceDir( EclipseManifestWriter.GENERATED_RESOURCE_DIRNAME, null, true, false, null, null,
248 false );
249 config.setSourceDirs( newSourceDirs );
250 }
251
252 if ( Constants.PROJECT_PACKAGING_WAR.equals( packaging ) )
253 {
254 new File( getWebContentBaseDirectory( config ) + File.separatorChar + "META-INF" ).mkdirs();
255 }
256
257
258
259
260 manifestWriter.write();
261 }
262
263
264
265
266
267
268
269
270
271 private void addDependencyToClassPath( StringBuffer classpath, IdeDependency dependency )
272 {
273 if ( !dependency.isTestDependency() && !dependency.isProvided()
274 && !dependency.isSystemScopedOutsideProject( this.config.getProject() ) )
275 {
276
277
278 if ( classpath.length() != 0 )
279 {
280 classpath.append( ' ' );
281 }
282
283
284 if ( !dependency.isReferencedProject() )
285 {
286 classpath.append( dependency.getFile().getName() );
287 }
288 else
289 {
290 classpath.append( dependency.getEclipseProjectName() + ".jar" );
291 }
292 }
293 }
294
295
296
297
298
299
300
301
302
303
304 private boolean areManifestsEqual( Manifest manifest, Manifest existingManifest )
305 {
306 if ( existingManifest == null )
307 {
308 return false;
309 }
310
311 Set keys = new HashSet();
312 Attributes existingMap = existingManifest.getMainAttributes();
313 Attributes newMap = manifest.getMainAttributes();
314 keys.addAll( existingMap.keySet() );
315 keys.addAll( newMap.keySet() );
316 Iterator iterator = keys.iterator();
317 while ( iterator.hasNext() )
318 {
319 Attributes.Name key = (Attributes.Name) iterator.next();
320 String newValue = (String) newMap.get( key );
321 String existingValue = (String) existingMap.get( key );
322
323
324 if ( Attributes.Name.CLASS_PATH.equals( key ) )
325 {
326 newValue = orderClasspath( newValue );
327 existingValue = orderClasspath( existingValue );
328 }
329 if ( ( newValue == null || !newValue.equals( existingValue ) )
330 && ( existingValue == null || !existingValue.equals( newValue ) ) )
331 {
332 return false;
333 }
334 }
335 return true;
336 }
337
338
339
340
341
342
343 private String constructManifestClasspath()
344 {
345 StringBuffer stringBuffer = new StringBuffer();
346 IdeDependency[] deps = this.config.getDepsOrdered();
347
348 for ( int index = 0; index < deps.length; index++ )
349 {
350 addDependencyToClassPath( stringBuffer, deps[index] );
351 }
352
353 return stringBuffer.toString();
354 }
355
356
357
358
359
360
361 private Manifest createNewManifest()
362 {
363 Manifest manifest = new Manifest();
364 manifest.getMainAttributes().put( Attributes.Name.MANIFEST_VERSION, "1.0" );
365 manifest.getMainAttributes().put( Attributes.Name.CLASS_PATH, constructManifestClasspath() );
366 return manifest;
367 }
368
369
370
371
372
373
374
375 private String orderClasspath( String newValue )
376 {
377 if ( newValue == null )
378 {
379 return null;
380 }
381 String[] entries = newValue.split( " " );
382 Arrays.sort( entries );
383 StringBuffer buffer = new StringBuffer( newValue.length() );
384 for ( int index = 0; index < entries.length; index++ )
385 {
386 buffer.append( entries[index] );
387 buffer.append( ' ' );
388 }
389 return buffer.toString();
390 }
391
392
393
394
395
396
397
398
399 private Manifest readExistingManifest( File manifestFile )
400 throws IOException
401 {
402 if ( !manifestFile.exists() )
403 {
404 return null;
405 }
406
407 Manifest existingManifest = new Manifest();
408 FileInputStream inputStream = new FileInputStream( manifestFile );
409 existingManifest.read( inputStream );
410 inputStream.close();
411 return existingManifest;
412 }
413
414
415
416
417
418
419
420
421
422
423 private boolean shouldNewManifestFileBeWritten( Manifest manifest, File manifestFile )
424 throws MojoExecutionException
425 {
426 try
427 {
428 Manifest existingManifest = readExistingManifest( manifestFile );
429 if ( areManifestsEqual( manifest, existingManifest ) )
430 {
431 this.log.info( Messages.getString( "EclipseCleanMojo.unchanged", manifestFile.getAbsolutePath() ) );
432 return false;
433 }
434 }
435 catch ( Exception e )
436 {
437 throw new MojoExecutionException( Messages.getString( "EclipseCleanMojo.nofilefound",
438 manifestFile.getAbsolutePath() ), e );
439 }
440 return true;
441 }
442 }