View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin.eclipse.writers;
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileOutputStream;
24  import java.io.IOException;
25  import java.io.InputStreamReader;
26  import java.io.OutputStreamWriter;
27  import java.io.Reader;
28  import java.io.Writer;
29  import java.util.ArrayList;
30  import java.util.Iterator;
31  import java.util.LinkedHashSet;
32  import java.util.List;
33  import java.util.Set;
34  
35  import org.apache.maven.model.Resource;
36  import org.apache.maven.plugin.MojoExecutionException;
37  import org.apache.maven.plugin.eclipse.BuildCommand;
38  import org.apache.maven.plugin.eclipse.LinkedResource;
39  import org.apache.maven.plugin.eclipse.Messages;
40  import org.apache.maven.plugin.ide.IdeDependency;
41  import org.apache.maven.plugin.ide.IdeUtils;
42  import org.codehaus.plexus.util.IOUtil;
43  import org.codehaus.plexus.util.StringUtils;
44  import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
45  import org.codehaus.plexus.util.xml.XMLWriter;
46  import org.codehaus.plexus.util.xml.Xpp3Dom;
47  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
48  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
49  
50  /**
51   * Writes eclipse .project file.
52   * 
53   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
54   * @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a>
55   * @author <a href="mailto:fgiust@apache.org">Fabrizio Giustina</a>
56   * @version $Id: EclipseProjectWriter.java 900005 2010-01-16 17:50:44Z bentmann $
57   */
58  public class EclipseProjectWriter
59      extends AbstractEclipseWriter
60  {
61      private static final String ELT_NAME = "name"; //$NON-NLS-1$
62  
63      private static final String ELT_COMMENT = "comment"; //$NON-NLS-1$
64  
65      private static final String ELT_BUILD_COMMAND = "buildCommand"; //$NON-NLS-1$
66  
67      private static final String ELT_LINK = "link"; //$NON-NLS-1$
68  
69      private static final String ELT_BUILD_SPEC = "buildSpec"; //$NON-NLS-1$
70  
71      private static final String ELT_LINKED_RESOURCES = "linkedResources"; //$NON-NLS-1$
72  
73      private static final String ELT_NATURE = "nature"; //$NON-NLS-1$
74  
75      private static final String ELT_NATURES = "natures"; //$NON-NLS-1$
76  
77      private static final String FILE_DOT_PROJECT = ".project"; //$NON-NLS-1$
78  
79      /**
80       * Constant for links to files.
81       */
82      private static final int LINK_TYPE_FILE = 1;
83  
84      /**
85       * Constant for links to directories.
86       */
87      private static final int LINK_TYPE_DIRECTORY = 2;
88  
89      /**
90       * To Store the link names
91       */
92      ArrayList linkNames = new ArrayList();
93  
94      /**
95       * @see org.apache.maven.plugin.eclipse.writers.EclipseWriter#write()
96       */
97      public void write()
98          throws MojoExecutionException
99      {
100 
101         Set projectnatures = new LinkedHashSet();
102         Set buildCommands = new LinkedHashSet();
103         Set linkedResources = new LinkedHashSet();
104 
105         File dotProject = new File( config.getEclipseProjectDirectory(), FILE_DOT_PROJECT );
106 
107         if ( dotProject.exists() )
108         {
109 
110             log.info( Messages.getString( "EclipsePlugin.keepexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
111 
112             // parse existing file in order to keep manually-added entries
113             Reader reader = null;
114             try
115             {
116                 reader = new InputStreamReader( new FileInputStream( dotProject ), "UTF-8" );
117                 Xpp3Dom dom = Xpp3DomBuilder.build( reader );
118 
119                 Xpp3Dom naturesElement = dom.getChild( ELT_NATURES );
120                 if ( naturesElement != null )
121                 {
122                     Xpp3Dom[] existingNatures = naturesElement.getChildren( ELT_NATURE );
123                     for ( int j = 0; j < existingNatures.length; j++ )
124                     {
125                         // adds all the existing natures
126                         projectnatures.add( existingNatures[j].getValue() );
127                     }
128                 }
129 
130                 Xpp3Dom buildSpec = dom.getChild( ELT_BUILD_SPEC );
131                 if ( buildSpec != null )
132                 {
133                     Xpp3Dom[] existingBuildCommands = buildSpec.getChildren( ELT_BUILD_COMMAND );
134                     for ( int j = 0; j < existingBuildCommands.length; j++ )
135                     {
136                         Xpp3Dom buildCommandName = existingBuildCommands[j].getChild( ELT_NAME );
137                         if ( buildCommandName != null )
138                         {
139                             buildCommands.add( new BuildCommand( existingBuildCommands[j] ) );
140                         }
141                     }
142                 }
143                 // Added the below code to preserve the Symbolic links
144                 Xpp3Dom linkedResourcesElement = dom.getChild( ELT_LINKED_RESOURCES );
145                 if ( linkedResourcesElement != null )
146                 {
147                     Xpp3Dom[] existingLinks = linkedResourcesElement.getChildren( ELT_LINK );
148                     for ( int j = 0; j < existingLinks.length; j++ )
149                     {
150                         Xpp3Dom linkName = existingLinks[j].getChild( ELT_NAME );
151                         if ( linkName != null )
152                         {
153                             // add all the existing symbolic links
154                             linkNames.add( existingLinks[j].getChild( ELT_NAME ).getValue() );
155                             linkedResources.add( new LinkedResource( existingLinks[j] ) );
156                         }
157                     }
158                 }
159 
160             }
161             catch ( XmlPullParserException e )
162             {
163                 log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
164             }
165             catch ( IOException e )
166             {
167                 log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
168             }
169             finally
170             {
171                 IOUtil.close( reader );
172             }
173         }
174 
175         // adds new entries after the existing ones
176         for ( Iterator iter = config.getProjectnatures().iterator(); iter.hasNext(); )
177         {
178             projectnatures.add( iter.next() );
179         }
180 
181         for ( Iterator iter = config.getBuildCommands().iterator(); iter.hasNext(); )
182         {
183             buildCommands.add( (BuildCommand) iter.next() );
184         }
185 
186         for ( Iterator iter = config.getLinkedResources().iterator(); iter.hasNext(); )
187         {
188             linkedResources.add( (LinkedResource) iter.next() );
189         }
190 
191         Writer w;
192 
193         try
194         {
195             w = new OutputStreamWriter( new FileOutputStream( dotProject ), "UTF-8" );
196         }
197         catch ( IOException ex )
198         {
199             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.erroropeningfile" ), ex ); //$NON-NLS-1$
200         }
201 
202         XMLWriter writer = new PrettyPrintXMLWriter( w );
203 
204         writer.startElement( "projectDescription" ); //$NON-NLS-1$
205 
206         writer.startElement( ELT_NAME );
207         writer.writeText( config.getEclipseProjectName() );
208         writer.endElement();
209 
210         addComment( writer, config.getProject().getDescription() );
211 
212         writer.startElement( "projects" ); //$NON-NLS-1$
213 
214         // referenced projects should not be added for plugins
215         if ( !config.isPde() )
216         {
217             List duplicates = new ArrayList();
218             for ( int j = 0; j < config.getDepsOrdered().length; j++ )
219             {
220                 IdeDependency dep = config.getDepsOrdered()[j];
221                 // Avoid duplicates entries when same project is refered using multiple types
222                 // (ejb, test-jar ...)
223                 if ( dep.isReferencedProject() && !duplicates.contains( dep.getEclipseProjectName() ) )
224                 {
225                     writer.startElement( "project" ); //$NON-NLS-1$
226                     writer.writeText( dep.getEclipseProjectName() );
227                     writer.endElement();
228                     duplicates.add( dep.getEclipseProjectName() );
229                 }
230             }
231         }
232 
233         writer.endElement(); // projects
234 
235         writer.startElement( ELT_BUILD_SPEC );
236 
237         for ( Iterator it = buildCommands.iterator(); it.hasNext(); )
238         {
239             ( (BuildCommand) it.next() ).print( writer );
240         }
241 
242         writer.endElement(); // buildSpec
243 
244         writer.startElement( ELT_NATURES );
245 
246         for ( Iterator it = projectnatures.iterator(); it.hasNext(); )
247         {
248             writer.startElement( ELT_NATURE );
249             writer.writeText( (String) it.next() );
250             writer.endElement(); // name
251         }
252 
253         writer.endElement(); // natures
254 
255         boolean addLinks = !config.getProjectBaseDir().equals( config.getEclipseProjectDirectory() );
256 
257         if ( addLinks || ( config.isPde() && config.getDepsOrdered().length > 0 ) || linkedResources.size() > 0 )
258         {
259             writer.startElement( "linkedResources" ); //$NON-NLS-1$
260             // preserve the symbolic links
261             if ( linkedResources.size() > 0 )
262             {
263                 for ( Iterator it = linkedResources.iterator(); it.hasNext(); )
264                 {
265                     ( (LinkedResource) it.next() ).print( writer );
266                 }
267             }
268 
269             if ( addLinks )
270             {
271 
272                 addFileLink( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
273                              config.getProject().getFile() );
274 
275                 addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
276                                 config.getProject().getCompileSourceRoots() );
277                 addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
278                                   config.getProject().getBuild().getResources() );
279 
280                 addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
281                                 config.getProject().getTestCompileSourceRoots() );
282                 addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
283                                   config.getProject().getBuild().getTestResources() );
284 
285             }
286 
287             if ( config.isPde() )
288             {
289                 for ( int j = 0; j < config.getDepsOrdered().length; j++ )
290                 {
291                     IdeDependency dep = config.getDepsOrdered()[j];
292 
293                     if ( dep.isAddedToClasspath() && !dep.isProvided() && !dep.isReferencedProject()
294                         && !dep.isTestDependency() && !dep.isOsgiBundle() )
295                     {
296                         String name = dep.getFile().getName();
297                         addLink( writer, name, StringUtils.replace( IdeUtils.getCanonicalPath( dep.getFile() ), "\\",
298                                                                     "/" ), LINK_TYPE_FILE );
299                     }
300                 }
301             }
302 
303             writer.endElement(); // linkedResources
304         }
305 
306         writer.endElement(); // projectDescription
307 
308         IOUtil.close( w );
309     }
310 
311     private void addFileLink( XMLWriter writer, File projectBaseDir, File basedir, File file )
312         throws MojoExecutionException
313     {
314         if ( file.isFile() )
315         {
316             String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, file, true );
317             String location = IdeUtils.getCanonicalPath( file ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
318 
319             addLink( writer, name, location, LINK_TYPE_FILE );
320         }
321         else
322         {
323             log.warn( Messages.getString( "EclipseProjectWriter.notafile", file ) ); //$NON-NLS-1$
324         }
325     }
326 
327     private void addSourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots )
328         throws MojoExecutionException
329     {
330         for ( Iterator it = sourceRoots.iterator(); it.hasNext(); )
331         {
332             String sourceRootString = (String) it.next();
333             File sourceRoot = new File( sourceRootString );
334 
335             if ( sourceRoot.isDirectory() )
336             {
337                 String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, sourceRoot, true );
338                 String location = IdeUtils.getCanonicalPath( sourceRoot ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
339 
340                 addLink( writer, name, location, LINK_TYPE_DIRECTORY );
341             }
342         }
343     }
344 
345     private void addResourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots )
346         throws MojoExecutionException
347     {
348         for ( Iterator it = sourceRoots.iterator(); it.hasNext(); )
349         {
350             String resourceDirString = ( (Resource) it.next() ).getDirectory();
351             File resourceDir = new File( resourceDirString );
352 
353             if ( resourceDir.isDirectory() )
354             {
355                 String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, resourceDir, true );
356                 String location = IdeUtils.getCanonicalPath( resourceDir ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
357 
358                 addLink( writer, name, location, LINK_TYPE_DIRECTORY );
359             }
360         }
361     }
362 
363     /**
364      * @param writer
365      * @param name
366      * @param location
367      */
368     private void addLink( XMLWriter writer, String name, String location, int type )
369     {
370         // Avoid duplicates entries of the link..
371         if ( !linkNames.contains( name ) )
372         {
373 
374             writer.startElement( "link" ); //$NON-NLS-1$
375 
376             writer.startElement( ELT_NAME );
377             writer.writeText( name );
378             writer.endElement(); // name
379 
380             writer.startElement( "type" ); //$NON-NLS-1$
381             writer.writeText( Integer.toString( type ) );
382             writer.endElement(); // type
383 
384             writer.startElement( "location" ); //$NON-NLS-1$
385 
386             writer.writeText( location );
387 
388             writer.endElement(); // location
389 
390             writer.endElement(); // link
391         }
392     }
393 
394     private void addComment( XMLWriter writer, String projectDescription )
395     {
396         String comment = "";
397 
398         if ( projectDescription != null )
399         {
400             comment = projectDescription.trim();
401 
402             if ( comment.length() > 0 )
403             {
404                 if ( !comment.endsWith( "." ) )
405                 {
406                     comment += ".";
407                 }
408                 comment += " ";
409             }
410         }
411 
412         //
413         // Project files that are generated with m-p-e cannot be supported by M2Eclipse
414         //
415         comment += "NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.";
416 
417         writer.startElement( ELT_COMMENT );
418         writer.writeText( comment );
419         writer.endElement();
420     }
421 
422 }