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.LinkedHashSet;
31  import java.util.List;
32  import java.util.Set;
33  
34  import org.apache.maven.model.Resource;
35  import org.apache.maven.plugin.MojoExecutionException;
36  import org.apache.maven.plugin.eclipse.BuildCommand;
37  import org.apache.maven.plugin.eclipse.LinkedResource;
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.xml.PrettyPrintXMLWriter;
43  import org.codehaus.plexus.util.xml.XMLWriter;
44  import org.codehaus.plexus.util.xml.Xpp3Dom;
45  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
46  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
47  
48  /**
49   * Writes eclipse .project file.
50   * 
51   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
52   * @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a>
53   * @author <a href="mailto:fgiust@apache.org">Fabrizio Giustina</a>
54   * @version $Id: EclipseProjectWriter.java 1672304 2015-04-09 12:04:28Z khmarbaise $
55   */
56  public class EclipseProjectWriter
57      extends AbstractEclipseWriter
58  {
59      private static final String ELT_NAME = "name"; //$NON-NLS-1$
60  
61      private static final String ELT_COMMENT = "comment"; //$NON-NLS-1$
62  
63      private static final String ELT_BUILD_COMMAND = "buildCommand"; //$NON-NLS-1$
64  
65      private static final String ELT_LINK = "link"; //$NON-NLS-1$
66  
67      private static final String ELT_BUILD_SPEC = "buildSpec"; //$NON-NLS-1$
68  
69      private static final String ELT_LINKED_RESOURCES = "linkedResources"; //$NON-NLS-1$
70  
71      private static final String ELT_NATURE = "nature"; //$NON-NLS-1$
72  
73      private static final String ELT_NATURES = "natures"; //$NON-NLS-1$
74  
75      private static final String FILE_DOT_PROJECT = ".project"; //$NON-NLS-1$
76  
77      /**
78       * Constant for links to files.
79       */
80      private static final int LINK_TYPE_FILE = 1;
81  
82      /**
83       * Constant for links to directories.
84       */
85      private static final int LINK_TYPE_DIRECTORY = 2;
86  
87      /**
88       * To Store the link names
89       */
90      ArrayList linkNames = new ArrayList();
91  
92      /**
93       * @see org.apache.maven.plugin.eclipse.writers.EclipseWriter#write()
94       */
95      public void write()
96          throws MojoExecutionException
97      {
98  
99          Set projectnatures = new LinkedHashSet();
100         Set buildCommands = new LinkedHashSet();
101         Set linkedResources = new LinkedHashSet();
102 
103         File dotProject = new File( config.getEclipseProjectDirectory(), FILE_DOT_PROJECT );
104 
105         if ( dotProject.exists() )
106         {
107 
108             log.info( Messages.getString( "EclipsePlugin.keepexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
109 
110             // parse existing file in order to keep manually-added entries
111             Reader reader = null;
112             try
113             {
114                 reader = new InputStreamReader( new FileInputStream( dotProject ), "UTF-8" );
115                 Xpp3Dom dom = Xpp3DomBuilder.build( reader );
116 
117                 Xpp3Dom naturesElement = dom.getChild( ELT_NATURES );
118                 if ( naturesElement != null )
119                 {
120                     Xpp3Dom[] existingNatures = naturesElement.getChildren( ELT_NATURE );
121                     for (Xpp3Dom existingNature : existingNatures) {
122                         // adds all the existing natures
123                         projectnatures.add(existingNature.getValue());
124                     }
125                 }
126 
127                 Xpp3Dom buildSpec = dom.getChild( ELT_BUILD_SPEC );
128                 if ( buildSpec != null )
129                 {
130                     Xpp3Dom[] existingBuildCommands = buildSpec.getChildren( ELT_BUILD_COMMAND );
131                     for (Xpp3Dom existingBuildCommand : existingBuildCommands) {
132                         Xpp3Dom buildCommandName = existingBuildCommand.getChild(ELT_NAME);
133                         if (buildCommandName != null) {
134                             buildCommands.add(new BuildCommand(existingBuildCommand));
135                         }
136                     }
137                 }
138                 // Added the below code to preserve the Symbolic links
139                 Xpp3Dom linkedResourcesElement = dom.getChild( ELT_LINKED_RESOURCES );
140                 if ( linkedResourcesElement != null )
141                 {
142                     Xpp3Dom[] existingLinks = linkedResourcesElement.getChildren( ELT_LINK );
143                     for (Xpp3Dom existingLink : existingLinks) {
144                         Xpp3Dom linkName = existingLink.getChild(ELT_NAME);
145                         if (linkName != null) {
146                             // add all the existing symbolic links
147                             linkNames.add(existingLink.getChild(ELT_NAME).getValue());
148                             linkedResources.add(new LinkedResource(existingLink));
149                         }
150                     }
151                 }
152 
153             }
154             catch ( XmlPullParserException e )
155             {
156                 log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
157             }
158             catch ( IOException e )
159             {
160                 log.warn( Messages.getString( "EclipsePlugin.cantparseexisting", dotProject.getAbsolutePath() ) ); //$NON-NLS-1$
161             }
162             finally
163             {
164                 IOUtil.close( reader );
165             }
166         }
167 
168         // adds new entries after the existing ones
169         for (Object o2 : config.getProjectnatures()) {
170             projectnatures.add(o2);
171         }
172 
173         for (Object o1 : config.getBuildCommands()) {
174             buildCommands.add(o1);
175         }
176 
177         for (Object o : config.getLinkedResources()) {
178             linkedResources.add(o);
179         }
180 
181         Writer w;
182 
183         try
184         {
185             w = new OutputStreamWriter( new FileOutputStream( dotProject ), "UTF-8" );
186         }
187         catch ( IOException ex )
188         {
189             throw new MojoExecutionException( Messages.getString( "EclipsePlugin.erroropeningfile" ), ex ); //$NON-NLS-1$
190         }
191 
192         XMLWriter writer = new PrettyPrintXMLWriter( w, "UTF-8", null );
193 
194         writer.startElement( "projectDescription" ); //$NON-NLS-1$
195 
196         writer.startElement( ELT_NAME );
197         writer.writeText( config.getEclipseProjectName() );
198         writer.endElement();
199 
200         addComment( writer, config.getProject().getDescription() );
201 
202         writer.startElement( "projects" ); //$NON-NLS-1$
203 
204         IdeDependency[] dependencies = config.getDeps();
205 
206         List duplicates = new ArrayList();
207         for (IdeDependency dep : dependencies) {
208             // Avoid duplicates entries when same project is refered using multiple types
209             // (ejb, test-jar ...)
210             if (dep.isReferencedProject() && !duplicates.contains(dep.getEclipseProjectName())) {
211                 writer.startElement("project"); //$NON-NLS-1$
212                 writer.writeText(dep.getEclipseProjectName());
213                 writer.endElement();
214                 duplicates.add(dep.getEclipseProjectName());
215             }
216         }
217 
218         writer.endElement(); // projects
219 
220         writer.startElement( ELT_BUILD_SPEC );
221 
222         for (Object buildCommand : buildCommands) {
223             ((BuildCommand) buildCommand).print(writer);
224         }
225 
226         writer.endElement(); // buildSpec
227 
228         writer.startElement( ELT_NATURES );
229 
230         for (Object projectnature : projectnatures) {
231             writer.startElement(ELT_NATURE);
232             writer.writeText((String) projectnature);
233             writer.endElement(); // name
234         }
235 
236         writer.endElement(); // natures
237 
238         boolean addLinks = !config.getProjectBaseDir().equals( config.getEclipseProjectDirectory() );
239 
240         if ( addLinks || linkedResources.size() > 0 )
241         {
242             writer.startElement( "linkedResources" ); //$NON-NLS-1$
243             // preserve the symbolic links
244             if ( linkedResources.size() > 0 )
245             {
246                 for (Object linkedResource : linkedResources) {
247                     ((LinkedResource) linkedResource).print(writer);
248                 }
249             }
250 
251             if ( addLinks )
252             {
253 
254                 addFileLink( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
255                              config.getProject().getFile() );
256 
257                 addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
258                                 config.getProject().getCompileSourceRoots() );
259                 addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
260                                   config.getProject().getBuild().getResources() );
261 
262                 addSourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
263                                 config.getProject().getTestCompileSourceRoots() );
264                 addResourceLinks( writer, config.getProjectBaseDir(), config.getEclipseProjectDirectory(),
265                                   config.getProject().getBuild().getTestResources() );
266 
267             }
268 
269             writer.endElement(); // linkedResources
270         }
271 
272         writer.endElement(); // projectDescription
273 
274         IOUtil.close( w );
275     }
276 
277     private void addFileLink( XMLWriter writer, File projectBaseDir, File basedir, File file )
278         throws MojoExecutionException
279     {
280         if ( file.isFile() )
281         {
282             String name = IdeUtils.toRelativeAndFixSeparator( projectBaseDir, file, true );
283             String location = IdeUtils.fixSeparator( IdeUtils.getCanonicalPath( file ) );
284 
285             addLink( writer, name, location, LINK_TYPE_FILE );
286         }
287         else
288         {
289             log.warn( Messages.getString( "EclipseProjectWriter.notafile", file ) ); //$NON-NLS-1$
290         }
291     }
292 
293     private void addSourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots )
294         throws MojoExecutionException
295     {
296         for (Object sourceRoot1 : sourceRoots) {
297             String sourceRootString = (String) sourceRoot1;
298             File sourceRoot = new File(sourceRootString);
299 
300             if (sourceRoot.isDirectory()) {
301                 String name = IdeUtils.toRelativeAndFixSeparator(projectBaseDir, sourceRoot, true);
302                 String location = IdeUtils.fixSeparator(IdeUtils.getCanonicalPath(sourceRoot));
303 
304                 addLink(writer, name, location, LINK_TYPE_DIRECTORY);
305             }
306         }
307     }
308 
309     private void addResourceLinks( XMLWriter writer, File projectBaseDir, File basedir, List sourceRoots )
310         throws MojoExecutionException
311     {
312         for (Object sourceRoot : sourceRoots) {
313             String resourceDirString = ((Resource) sourceRoot).getDirectory();
314             File resourceDir = new File(resourceDirString);
315 
316             if (resourceDir.isDirectory()) {
317                 String name = IdeUtils.toRelativeAndFixSeparator(projectBaseDir, resourceDir, true);
318                 String location = IdeUtils.fixSeparator(IdeUtils.getCanonicalPath(resourceDir));
319 
320                 addLink(writer, name, location, LINK_TYPE_DIRECTORY);
321             }
322         }
323     }
324 
325     /**
326      * @param writer
327      * @param name
328      * @param location
329      */
330     private void addLink( XMLWriter writer, String name, String location, int type )
331     {
332         // Avoid duplicates entries of the link..
333         if ( !linkNames.contains( name ) )
334         {
335 
336             writer.startElement( "link" ); //$NON-NLS-1$
337 
338             writer.startElement( ELT_NAME );
339             writer.writeText( name );
340             writer.endElement(); // name
341 
342             writer.startElement( "type" ); //$NON-NLS-1$
343             writer.writeText( Integer.toString( type ) );
344             writer.endElement(); // type
345 
346             writer.startElement( "location" ); //$NON-NLS-1$
347 
348             writer.writeText( location );
349 
350             writer.endElement(); // location
351 
352             writer.endElement(); // link
353         }
354     }
355 
356     private void addComment( XMLWriter writer, String projectDescription )
357     {
358         String comment = "";
359 
360         if ( projectDescription != null )
361         {
362             comment = projectDescription.trim();
363 
364             if ( comment.length() > 0 )
365             {
366                 if ( !comment.endsWith( "." ) )
367                 {
368                     comment += ".";
369                 }
370                 comment += " ";
371             }
372         }
373 
374         //
375         // Project files that are generated with m-p-e cannot be supported by M2Eclipse
376         //
377         comment += "NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse.";
378 
379         writer.startElement( ELT_COMMENT );
380         writer.writeText( comment );
381         writer.endElement();
382     }
383 
384 }