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.Messages;
39  import org.apache.maven.plugin.ide.IdeDependency;
40  import org.apache.maven.plugin.ide.IdeUtils;
41  import org.codehaus.plexus.util.IOUtil;
42  import org.codehaus.plexus.util.StringUtils;
43  import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
44  import org.codehaus.plexus.util.xml.XMLWriter;
45  import org.codehaus.plexus.util.xml.Xpp3Dom;
46  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
47  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
48  
49  /**
50   * Writes eclipse .project file.
51   * 
52   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
53   * @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a>
54   * @author <a href="mailto:fgiust@apache.org">Fabrizio Giustina</a>
55   * @version $Id: EclipseProjectWriter.java 728546 2008-12-21 22:56:51Z bentmann $
56   */
57  public class EclipseProjectWriter
58      extends AbstractEclipseWriter
59  {
60      private static final String ELT_NAME = "name"; //$NON-NLS-1$
61  
62      private static final String ELT_BUILD_COMMAND = "buildCommand"; //$NON-NLS-1$
63  
64      private static final String ELT_BUILD_SPEC = "buildSpec"; //$NON-NLS-1$
65  
66      private static final String ELT_NATURE = "nature"; //$NON-NLS-1$
67  
68      private static final String ELT_NATURES = "natures"; //$NON-NLS-1$
69  
70      private static final String FILE_DOT_PROJECT = ".project"; //$NON-NLS-1$
71  
72      /**
73       * Constant for links to files.
74       */
75      private static final int LINK_TYPE_FILE = 1;
76  
77      /**
78       * Constant for links to directories.
79       */
80      private static final int LINK_TYPE_DIRECTORY = 2;
81  
82      /**
83       * @see org.apache.maven.plugin.eclipse.writers.EclipseWriter#write()
84       */
85      public void write()
86          throws MojoExecutionException
87      {
88  
89          Set projectnatures = new LinkedHashSet();
90          Set buildCommands = new LinkedHashSet();
91  
92          File dotProject = new File( config.getEclipseProjectDirectory(), FILE_DOT_PROJECT );
93  
94          if ( dotProject.exists() )
95          {
96  
97              log.info( Messages.getString( "EclipsePlugin.keepexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
98  
99              // parse existing file in order to keep manually-added entries
100             Reader reader = null;
101             try
102             {
103                 reader = new InputStreamReader( new FileInputStream( dotProject ), "UTF-8" );
104                 Xpp3Dom dom = Xpp3DomBuilder.build( reader );
105 
106                 Xpp3Dom naturesElement = dom.getChild( ELT_NATURES );
107                 if ( naturesElement != null )
108                 {
109                     Xpp3Dom[] existingNatures = naturesElement.getChildren( ELT_NATURE );
110                     for ( int j = 0; j < existingNatures.length; j++ )
111                     {
112                         // adds all the existing natures
113                         projectnatures.add( existingNatures[j].getValue() );
114                     }
115                 }
116 
117                 Xpp3Dom buildSpec = dom.getChild( ELT_BUILD_SPEC );
118                 if ( buildSpec != null )
119                 {
120                     Xpp3Dom[] existingBuildCommands = buildSpec.getChildren( ELT_BUILD_COMMAND );
121                     for ( int j = 0; j < existingBuildCommands.length; j++ )
122                     {
123                         Xpp3Dom buildCommandName = existingBuildCommands[j].getChild( ELT_NAME );
124                         if ( buildCommandName != null )
125                         {
126                             buildCommands.add( new BuildCommand( existingBuildCommands[j] ) );
127                         }
128                     }
129                 }
130             }
131             catch ( XmlPullParserException e )
132             {
133                 log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
134             }
135             catch ( IOException e )
136             {
137                 log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
138             }
139             finally
140             {
141                 IOUtil.close( reader );
142             }
143         }
144 
145         // adds new entries after the existing ones
146         for ( Iterator iter = config.getProjectnatures().iterator(); iter.hasNext(); )
147         {
148             projectnatures.add( iter.next() );
149         }
150 
151         for ( Iterator iter = config.getBuildCommands().iterator(); iter.hasNext(); )
152         {
153             buildCommands.add( (BuildCommand) iter.next() );
154         }
155 
156         Writer w;
157 
158         try
159         {
160             w = new OutputStreamWriter( new FileOutputStream( dotProject ), "UTF-8" );
161         }
162         catch ( IOException ex )
163         {
164             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.erroropeningfile" ), ex ); //$NON-NLS-1$
165         }
166 
167         XMLWriter writer = new PrettyPrintXMLWriter( w );
168 
169         writer.startElement( "projectDescription" ); //$NON-NLS-1$
170 
171         writer.startElement( ELT_NAME );
172         writer.writeText( config.getEclipseProjectName() );
173         writer.endElement();
174 
175         // TODO: this entire element might be dropped if the comment is null.
176         // but as the maven1 eclipse plugin does it, it's better to be safe than sorry
177         // A eclipse developer might want to look at this.
178         writer.startElement( "comment" ); //$NON-NLS-1$
179 
180         if ( config.getProject().getDescription() != null )
181         {
182             writer.writeText( config.getProject().getDescription() );
183         }
184 
185         writer.endElement();
186 
187         writer.startElement( "projects" ); //$NON-NLS-1$
188 
189         // referenced projects should not be added for plugins
190         if ( !config.isPde() )
191         {
192             List duplicates = new ArrayList();
193             for ( int j = 0; j < config.getDepsOrdered().length; j++ )
194             {
195                 IdeDependency dep = config.getDepsOrdered()[j];
196                 // Avoid duplicates entries when same project is refered using multiple types
197                 // (ejb, test-jar ...)
198                 if ( dep.isReferencedProject() && !duplicates.contains( dep.getEclipseProjectName() ) )
199                 {
200                     writer.startElement( "project" ); //$NON-NLS-1$
201                     writer.writeText( dep.getEclipseProjectName() );
202                     writer.endElement();
203                     duplicates.add( dep.getEclipseProjectName() );
204                 }
205             }
206         }
207 
208         writer.endElement(); // projects
209 
210         writer.startElement( ELT_BUILD_SPEC );
211 
212         for ( Iterator it = buildCommands.iterator(); it.hasNext(); )
213         {
214             ( (BuildCommand) it.next() ).print( writer );
215         }
216 
217         writer.endElement(); // buildSpec
218 
219         writer.startElement( ELT_NATURES );
220 
221         for ( Iterator it = projectnatures.iterator(); it.hasNext(); )
222         {
223             writer.startElement( ELT_NATURE );
224             writer.writeText( (String) it.next() );
225             writer.endElement(); // name
226         }
227 
228         writer.endElement(); // natures
229 
230         boolean addLinks = !config.getProjectBaseDir().equals( config.getEclipseProjectDirectory() );
231 
232         if ( addLinks || ( config.isPde() && config.getDepsOrdered().length > 0 ) )
233         {
234             writer.startElement( "linkedResources" ); //$NON-NLS-1$
235 
236             if ( addLinks )
237             {
238 
239                 addFileLink( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
240                              config.getProject().getFile() );
241 
242                 addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
243                                 config.getProject().getCompileSourceRoots() );
244                 addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
245                                   config.getProject().getBuild().getResources() );
246 
247                 addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
248                                 config.getProject().getTestCompileSourceRoots() );
249                 addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
250                                   config.getProject().getBuild().getTestResources() );
251 
252             }
253 
254             if ( config.isPde() )
255             {
256                 for ( int j = 0; j < config.getDepsOrdered().length; j++ )
257                 {
258                     IdeDependency dep = config.getDepsOrdered()[j];
259 
260                     if ( dep.isAddedToClasspath() && !dep.isProvided() && !dep.isReferencedProject()
261                         && !dep.isTestDependency() && !dep.isOsgiBundle() )
262                     {
263                         String name = dep.getFile().getName();
264                         addLink( writer, name, StringUtils.replace( IdeUtils.getCanonicalPath( dep.getFile() ), "\\",
265                                                                     "/" ), LINK_TYPE_FILE );
266                     }
267                 }
268             }
269 
270             writer.endElement(); // linkedResources
271         }
272 
273         writer.endElement(); // projectDescription
274 
275         IOUtil.close( w );
276     }
277 
278     private void addFileLink( XMLWriter writer, File projectBaseDir, File basedir, File file )
279         throws MojoExecutionException
280     {
281         if ( file.isFile() )
282         {
283             String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, file, true );
284             String location = IdeUtils.getCanonicalPath( file ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
285 
286             addLink( writer, name, location, LINK_TYPE_FILE );
287         }
288         else
289         {
290             log.warn( Messages.getString( "EclipseProjectWriter.notafile", file ) ); //$NON-NLS-1$
291         }
292     }
293 
294     private void addSourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots )
295         throws MojoExecutionException
296     {
297         for ( Iterator it = sourceRoots.iterator(); it.hasNext(); )
298         {
299             String sourceRootString = (String) it.next();
300             File sourceRoot = new File( sourceRootString );
301 
302             if ( sourceRoot.isDirectory() )
303             {
304                 String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, sourceRoot, true );
305                 String location = IdeUtils.getCanonicalPath( sourceRoot ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
306 
307                 addLink( writer, name, location, LINK_TYPE_DIRECTORY );
308             }
309         }
310     }
311 
312     private void addResourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots )
313         throws MojoExecutionException
314     {
315         for ( Iterator it = sourceRoots.iterator(); it.hasNext(); )
316         {
317             String resourceDirString = ( (Resource) it.next() ).getDirectory();
318             File resourceDir = new File( resourceDirString );
319 
320             if ( resourceDir.isDirectory() )
321             {
322                 String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, resourceDir, true );
323                 String location = IdeUtils.getCanonicalPath( resourceDir ).replaceAll( "\\\\", "/" ); //$NON-NLS-1$ //$NON-NLS-2$
324 
325                 addLink( writer, name, location, LINK_TYPE_DIRECTORY );
326             }
327         }
328     }
329 
330     /**
331      * @param writer
332      * @param name
333      * @param location
334      */
335     private void addLink( XMLWriter writer, String name, String location, int type )
336     {
337         writer.startElement( "link" ); //$NON-NLS-1$
338 
339         writer.startElement( ELT_NAME );
340         writer.writeText( name );
341         writer.endElement(); // name
342 
343         writer.startElement( "type" ); //$NON-NLS-1$
344         writer.writeText( Integer.toString( type ) );
345         writer.endElement(); // type
346 
347         writer.startElement( "location" ); //$NON-NLS-1$
348 
349         writer.writeText( location );
350 
351         writer.endElement(); // location
352 
353         writer.endElement(); // link
354     }
355 }