1 package org.codehaus.mojo.siteskinner;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.text.SimpleDateFormat;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Date;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Properties;
34 import java.util.StringTokenizer;
35 import java.util.jar.JarEntry;
36 import java.util.jar.JarFile;
37
38 import org.apache.commons.cli.CommandLine;
39 import org.apache.commons.cli.ParseException;
40 import org.apache.maven.artifact.Artifact;
41 import org.apache.maven.artifact.factory.ArtifactFactory;
42 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
43 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
44 import org.apache.maven.artifact.repository.ArtifactRepository;
45 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
46 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
47 import org.apache.maven.artifact.resolver.ArtifactResolver;
48 import org.apache.maven.artifact.versioning.ArtifactVersion;
49 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
50 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
51 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
52 import org.apache.maven.artifact.versioning.VersionRange;
53 import org.apache.maven.doxia.site.decoration.Body;
54 import org.apache.maven.doxia.site.decoration.DecorationModel;
55 import org.apache.maven.doxia.site.decoration.PublishDate;
56 import org.apache.maven.doxia.site.decoration.io.xpp3.DecorationXpp3Reader;
57 import org.apache.maven.doxia.site.decoration.io.xpp3.DecorationXpp3Writer;
58 import org.apache.maven.doxia.tools.SiteTool;
59 import org.apache.maven.doxia.tools.SiteToolException;
60 import org.apache.maven.model.Plugin;
61 import org.apache.maven.plugin.AbstractMojo;
62 import org.apache.maven.plugin.MojoExecutionException;
63 import org.apache.maven.plugin.MojoFailureException;
64 import org.apache.maven.plugins.annotations.Component;
65 import org.apache.maven.plugins.annotations.Mojo;
66 import org.apache.maven.plugins.annotations.Parameter;
67 import org.apache.maven.project.MavenProject;
68 import org.apache.maven.project.MavenProjectBuilder;
69 import org.apache.maven.project.ProjectBuildingException;
70 import org.apache.maven.scm.manager.ScmManager;
71 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
72 import org.apache.maven.shared.invoker.InvocationRequest;
73 import org.apache.maven.shared.invoker.InvocationResult;
74 import org.apache.maven.shared.invoker.Invoker;
75 import org.apache.maven.shared.invoker.InvokerLogger;
76 import org.apache.maven.shared.invoker.MavenInvocationException;
77 import org.codehaus.plexus.util.FileUtils;
78 import org.codehaus.plexus.util.IOUtil;
79 import org.codehaus.plexus.util.ReaderFactory;
80 import org.codehaus.plexus.util.StringUtils;
81 import org.codehaus.plexus.util.WriterFactory;
82 import org.codehaus.plexus.util.cli.CommandLineUtils;
83 import org.codehaus.plexus.util.xml.Xpp3Dom;
84 import org.codehaus.plexus.util.xml.Xpp3DomUtils;
85 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
86
87
88
89
90
91
92
93 @Mojo( name = "skin", requiresDirectInvocation = true, aggregator = true )
94 public class SkinMojo
95 extends AbstractMojo
96 {
97 private static final String MAVEN_SITE_PLUGIN_KEY = "org.apache.maven.plugins:maven-site-plugin";
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 @Parameter( property = "mavenHome" )
123 private File mavenHome;
124
125
126
127
128
129
130
131
132
133
134 @Parameter( property = "arguments" )
135 private String arguments;
136
137
138
139
140
141 @Parameter( property = "forceCheckout", defaultValue = "false" )
142 private boolean forceCheckout;
143
144
145
146
147
148
149 @Parameter( property = "mergeBody", defaultValue = "true" )
150 private boolean mergeBody;
151
152
153
154
155
156
157 @Parameter( property = "siteDeploy", defaultValue = "false" )
158 private boolean siteDeploy;
159
160
161
162
163
164 @Parameter( property = "siteskinner.publishDate" )
165 private String publishDate;
166
167
168
169
170
171 @Parameter( defaultValue = "${project.build.sourceEncoding}", property = "encoding" )
172 private String inputEncoding;
173
174
175
176
177
178 @Parameter( defaultValue = "${project.reporting.outputEncoding}", property = "outputEncoding" )
179 private String outputEncoding;
180
181
182
183
184
185
186 @Parameter( defaultValue = "(,${project.version})", readonly = true )
187 private String releasedVersion;
188
189
190
191
192 @Parameter( defaultValue = "${project.build.directory}/siteskinner", readonly = true )
193 private File workingDirectory;
194
195
196
197
198 @Parameter( defaultValue = "${reactorProjects}", readonly = true, required = true )
199 private List<MavenProject> reactorProjects;
200
201
202
203
204
205
206 private String getInputEncoding()
207 {
208 return ( inputEncoding == null ) ? ReaderFactory.ISO_8859_1 : inputEncoding;
209 }
210
211
212
213
214
215
216 private String getOutputEncoding()
217 {
218 return ( outputEncoding == null ) ? WriterFactory.UTF_8 : outputEncoding;
219 }
220
221 @Component
222 private MavenProject currentProject;
223
224
225
226
227 @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
228 private ArtifactRepository localRepository;
229
230
231
232
233 @Parameter( property = "settingsFile" )
234 private File settingsFile;
235
236
237
238
239 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true )
240 private List<ArtifactRepository> remoteRepositories;
241
242 @Component
243 private MavenProjectBuilder mavenProjectBuilder;
244
245 @Component
246 private ScmManager scmManager;
247
248 @Component
249 private ArtifactMetadataSource metadataSource;
250
251 @Component
252 private ArtifactFactory factory;
253
254 @Component
255 private ArtifactResolver resolver;
256
257 @Component
258 private SiteTool siteTool;
259
260 @Component
261 private Invoker invoker;
262
263
264 public void execute()
265 throws MojoExecutionException, MojoFailureException
266 {
267 MavenProject releasedProject;
268 Artifact releasedArtifact;
269 try
270 {
271 releasedArtifact = resolveArtifact( releasedVersion );
272 MavenProject externalProject =
273 mavenProjectBuilder.buildFromRepository( releasedArtifact, remoteRepositories, localRepository );
274
275 fetchSources( workingDirectory, externalProject );
276
277 releasedProject =
278 mavenProjectBuilder.build( new File( workingDirectory, "pom.xml" ), localRepository, null );
279 }
280 catch ( ProjectBuildingException e )
281 {
282 throw new MojoExecutionException( e.getMessage() );
283 }
284
285 verifyVersionCompatibility( releasedProject );
286
287 Xpp3Dom releasedConfig = getSitePluginConfiguration( releasedProject );
288 String releasedSiteDirectory =
289 releasedConfig == null || releasedConfig.getChild( "siteDirectory" ) == null ? "src/site"
290 : releasedConfig.getChild( "siteDirectory" ).getValue();
291 String releasedLocales =
292 ( releasedConfig == null || releasedConfig.getChild( "locales" ) == null ? null
293 : releasedConfig.getChild( "locales" ).getValue() );
294
295 Xpp3Dom currentConfig = getSitePluginConfiguration( currentProject );
296 String currentSiteDirectory =
297 currentConfig == null || currentConfig.getChild( "siteDirectory" ) == null ? "src/site"
298 : currentConfig.getChild( "siteDirectory" ).getValue();
299 try
300 {
301 DecorationXpp3Writer writer = new DecorationXpp3Writer();
302 DecorationXpp3Reader reader = new DecorationXpp3Reader();
303
304 for ( Locale locale : siteTool.getAvailableLocales( releasedLocales ) )
305 {
306 DecorationModel resolvedCurrentModel;
307 try
308 {
309 resolvedCurrentModel =
310 siteTool.getDecorationModel( currentProject, reactorProjects, localRepository,
311 remoteRepositories, currentSiteDirectory, locale,
312 getInputEncoding(), getOutputEncoding() );
313 }
314 catch ( SiteToolException e )
315 {
316 getLog().warn( e.getMessage(), e );
317 continue;
318 }
319
320 if ( resolvedCurrentModel.getSkin() == null )
321 {
322 throw new MojoFailureException(
323 "No skin defined in the current project, neither inherited; Can't apply a new skin on the old site." );
324 }
325
326 File currentSiteXml =
327 siteTool.getSiteDescriptorFromBasedir( currentSiteDirectory, currentProject.getBasedir(), locale );
328
329 DecorationModel currentModel;
330 if ( currentSiteXml.exists() )
331 {
332 currentModel = readDecorationModel( reader, currentSiteXml );
333 }
334 else
335 {
336 currentModel = new DecorationModel();
337 }
338
339 File releasedSiteXml =
340 siteTool.getSiteDescriptorFromBasedir( releasedSiteDirectory, releasedProject.getBasedir(), locale );
341
342 DecorationModel releasedModel = null;
343 if ( releasedSiteXml.exists() )
344 {
345 releasedModel = readDecorationModel( reader, releasedSiteXml );
346 }
347 else
348 {
349
350 releasedSiteXml.getParentFile().mkdirs();
351 releasedModel = new DecorationModel();
352 }
353
354 releasedModel.setSkin( resolvedCurrentModel.getSkin() );
355
356 releasedModel.setBannerLeft( currentModel.getBannerLeft() );
357 releasedModel.setBannerRight( currentModel.getBannerRight() );
358 releasedModel.setGoogleAnalyticsAccountId( currentModel.getGoogleAnalyticsAccountId() );
359 releasedModel.setModelEncoding( currentModel.getModelEncoding() );
360 releasedModel.setName( currentModel.getName() );
361 releasedModel.setPoweredBy( currentModel.getPoweredBy() );
362 releasedModel.setPublishDate( currentModel.getPublishDate() );
363 releasedModel.setVersion( currentModel.getVersion() );
364
365 if ( mergeBody && currentModel.getBody() != null )
366 {
367 if ( releasedModel.getBody() == null )
368 {
369 releasedModel.setBody( new Body() );
370 }
371 releasedModel.getBody().setBreadcrumbs( currentModel.getBody().getBreadcrumbs() );
372 releasedModel.getBody().setFooter( currentModel.getBody().getFooter() );
373 releasedModel.getBody().setHead( currentModel.getBody().getHead() );
374 releasedModel.getBody().setLinks( currentModel.getBody().getLinks() );
375 }
376
377 Xpp3Dom mergedCustom =
378 Xpp3DomUtils.mergeXpp3Dom( (Xpp3Dom) currentModel.getCustom(), (Xpp3Dom) releasedModel.getCustom() );
379
380 if ( mergedCustom == null )
381 {
382 mergedCustom = new Xpp3Dom( "custom" );
383 }
384
385 String publishDateFormat;
386 if ( releasedModel.getPublishDate() != null )
387 {
388 publishDateFormat = releasedModel.getPublishDate().getFormat();
389 }
390 else
391 {
392 publishDateFormat = new PublishDate().getFormat();
393 }
394
395 Xpp3Dom publishDateChild = new Xpp3Dom( "publishDate" );
396
397 String publishDateValue;
398
399 if ( publishDate == null )
400 {
401 long preResolveDate = System.currentTimeMillis();
402
403 try
404 {
405 resolver.resolveAlways( releasedArtifact, remoteRepositories, localRepository );
406 }
407 catch ( ArtifactResolutionException e )
408 {
409 throw new MojoExecutionException( e.getMessage() );
410 }
411 catch ( ArtifactNotFoundException e )
412 {
413 throw new MojoExecutionException( e.getMessage() );
414 }
415
416 long deployDate;
417 if ( releasedArtifact.getFile().lastModified() < preResolveDate )
418 {
419
420 deployDate = releasedArtifact.getFile().lastModified();
421 }
422 else
423 {
424
425 JarFile jarFile = new JarFile( releasedArtifact.getFile() );
426 JarEntry entry = jarFile.entries().nextElement();
427
428 deployDate = entry.getTime();
429 }
430 Date releaseDate = new Date( deployDate );
431
432 publishDateValue = new SimpleDateFormat( publishDateFormat ).format( releaseDate );
433 }
434 else
435 {
436
437 try
438 {
439 new SimpleDateFormat( publishDateFormat ).parse( publishDate );
440 }
441 catch ( java.text.ParseException e )
442 {
443 throw new MojoExecutionException( e.getMessage() );
444 }
445 publishDateValue = publishDate;
446 }
447
448 publishDateChild.setValue( publishDateValue );
449 mergedCustom.addChild( publishDateChild );
450 releasedModel.setCustom( mergedCustom );
451
452 FileOutputStream fileOutputStream = new FileOutputStream( releasedSiteXml );
453 try
454 {
455 writer.write( fileOutputStream, releasedModel );
456 }
457 finally
458 {
459 IOUtil.close( fileOutputStream );
460 }
461
462 }
463 }
464 catch ( IOException e )
465 {
466 throw new MojoExecutionException( e.getMessage() );
467 }
468 catch ( XmlPullParserException e )
469 {
470 throw new MojoExecutionException( e.getMessage() );
471 }
472
473 InvocationRequest request = buildInvokerRequest( releasedProject );
474
475 invoker.setLocalRepositoryDirectory( new File( localRepository.getBasedir() ) );
476 invoker.setMavenHome( mavenHome );
477
478 if ( getLog().isDebugEnabled() )
479 {
480 invoker.getLogger().setThreshold( InvokerLogger.DEBUG );
481 }
482 else if ( getLog().isInfoEnabled() )
483 {
484 invoker.getLogger().setThreshold( InvokerLogger.INFO );
485 }
486 else if ( getLog().isWarnEnabled() )
487 {
488 invoker.getLogger().setThreshold( InvokerLogger.WARN );
489 }
490 else if ( getLog().isErrorEnabled() )
491 {
492 invoker.getLogger().setThreshold( InvokerLogger.ERROR );
493 }
494
495 try
496 {
497 InvocationResult invocationResult = invoker.execute( request );
498 if ( invocationResult.getExitCode() != 0 )
499 {
500 throw new MojoExecutionException( invocationResult.getExecutionException().getMessage() );
501 }
502 }
503 catch ( MavenInvocationException e )
504 {
505 throw new MojoExecutionException( e.getMessage() );
506 }
507 }
508
509 private InvocationRequest buildInvokerRequest( MavenProject releasedProject )
510 throws MojoFailureException
511 {
512 InvocationRequest request = new DefaultInvocationRequest();
513 request.setGoals( Collections.singletonList( siteDeploy ? "site-deploy" : "site" ) );
514 request.setPomFile( releasedProject.getFile() );
515 request.setShowErrors( true );
516 request.setUserSettingsFile( settingsFile );
517
518 if ( arguments != null )
519 {
520 try
521 {
522 String[] args = CommandLineUtils.translateCommandline( arguments );
523 CLIManager cliManager = new CLIManager();
524 CommandLine cl = cliManager.parse( args );
525 request.setDebug( cl.hasOption( CLIManager.DEBUG ) );
526
527
528
529
530 List<String> profiles = new ArrayList<String>();
531
532 if ( cl.hasOption( CLIManager.ACTIVATE_PROFILES ) )
533 {
534 String[] profileOptionValues = cl.getOptionValues( CLIManager.ACTIVATE_PROFILES );
535 if ( profileOptionValues != null )
536 {
537 for ( String profileOptionValue : profileOptionValues )
538 {
539 StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," );
540
541 while ( profileTokens.hasMoreTokens() )
542 {
543 profiles.add( profileTokens.nextToken().trim() );
544 }
545 }
546 }
547 request.setProfiles( profiles );
548 }
549
550 if ( cl.hasOption( CLIManager.SET_SYSTEM_PROPERTY ) )
551 {
552 Properties userProperties = new Properties();
553 String[] defStrs = cl.getOptionValues( CLIManager.SET_SYSTEM_PROPERTY );
554
555 if ( defStrs != null )
556 {
557 for ( String defStr : defStrs )
558 {
559 setCliProperty( defStr, userProperties );
560 }
561 }
562 request.setProperties( userProperties );
563 }
564 }
565 catch ( ParseException e )
566 {
567 throw new MojoFailureException( "Unsupported option: " + e.getMessage() );
568 }
569 catch ( Exception e )
570 {
571 throw new MojoFailureException( e.getMessage() );
572 }
573 }
574 return request;
575 }
576
577 private DecorationModel readDecorationModel( DecorationXpp3Reader reader, File currentSiteXml )
578 throws IOException, XmlPullParserException
579 {
580 DecorationModel currentModel;
581 FileInputStream fileInputStream = new FileInputStream( currentSiteXml );
582 try
583 {
584 currentModel = reader.read( fileInputStream, false );
585 }
586 finally
587 {
588 IOUtil.close( fileInputStream );
589 }
590 return currentModel;
591 }
592
593
594
595
596
597
598
599
600 private void verifyVersionCompatibility( MavenProject releasedProject )
601 throws MojoFailureException
602 {
603
604 ArtifactVersion sitePluginVersion = getSitePluginVersion( releasedProject );
605
606 String mavenVersion;
607 if ( mavenHome == null )
608 {
609 mavenVersion = SelectorUtils.getMavenVersion();
610 }
611 else
612 {
613 mavenVersion = SelectorUtils.getMavenVersion( mavenHome );
614 }
615
616 if ( sitePluginVersion != null )
617 {
618 try
619 {
620 if ( VersionRange.createFromVersionSpec( "(,3.0-alpha-1)" ).containsVersion( sitePluginVersion )
621 && VersionRange.createFromVersionSpec( "[3.0,)" ).containsVersion( new DefaultArtifactVersion(
622 mavenVersion ) ) )
623 {
624 throw new MojoFailureException( "maven-site-plugin:" + sitePluginVersion
625 + " can only be executed with Maven 2.x" );
626 }
627 else if ( VersionRange.createFromVersionSpec( "[3.0-alpha-1,3.0)" ).containsVersion( sitePluginVersion )
628 && VersionRange.createFromVersionSpec( "(, 3.0)" ).containsVersion( new DefaultArtifactVersion(
629 mavenVersion ) ) )
630 {
631 throw new MojoFailureException( "maven-site-plugin:" + sitePluginVersion
632 + " can only be executed with Maven 3.x+" );
633 }
634 }
635 catch ( InvalidVersionSpecificationException e )
636 {
637 throw new MojoFailureException( e.getMessage() );
638 }
639 }
640 }
641
642 private Xpp3Dom getSitePluginConfiguration( MavenProject releasedProject )
643 {
644 Plugin sitePlugin = (Plugin) releasedProject.getBuild().getPluginsAsMap().get( MAVEN_SITE_PLUGIN_KEY );
645 if ( sitePlugin == null )
646 {
647 sitePlugin =
648 (Plugin) releasedProject.getBuild().getPluginManagement().getPluginsAsMap().get( MAVEN_SITE_PLUGIN_KEY );
649 }
650 return (Xpp3Dom) sitePlugin.getConfiguration();
651 }
652
653 private ArtifactVersion getSitePluginVersion( MavenProject releasedProject )
654 {
655 ArtifactVersion sitePluginVersion = null;
656 Plugin sitePlugin = (Plugin) releasedProject.getBuild().getPluginsAsMap().get( MAVEN_SITE_PLUGIN_KEY );
657 if ( sitePlugin == null )
658 {
659 sitePlugin =
660 (Plugin) releasedProject.getBuild().getPluginManagement().getPluginsAsMap().get( MAVEN_SITE_PLUGIN_KEY );
661 }
662
663 if ( sitePlugin != null && sitePlugin.getVersion() != null )
664 {
665 sitePluginVersion = new DefaultArtifactVersion( sitePlugin.getVersion() );
666 }
667 return sitePluginVersion;
668 }
669
670 private String getConnection( MavenProject mavenProject )
671 throws MojoFailureException
672 {
673 if ( mavenProject.getScm() == null )
674 {
675 throw new MojoFailureException( "SCM is not set in your pom.xml." );
676 }
677
678 String connection = mavenProject.getScm().getConnection();
679
680 if ( connection != null )
681 {
682 if ( connection.length() > 0 )
683 {
684 return connection;
685 }
686 }
687 connection = mavenProject.getScm().getDeveloperConnection();
688
689 if ( StringUtils.isEmpty( connection ) )
690 {
691 throw new MojoFailureException( "SCM Connection is not set in your pom.xml." );
692 }
693 return connection;
694 }
695
696 private Artifact resolveArtifact( String versionSpec )
697 throws MojoFailureException, MojoExecutionException
698 {
699
700 VersionRange range;
701 try
702 {
703 range = VersionRange.createFromVersionSpec( versionSpec );
704 }
705 catch ( InvalidVersionSpecificationException e )
706 {
707 throw new MojoFailureException( "Invalid comparison version: " + e.getMessage() );
708 }
709
710 Artifact previousArtifact;
711 try
712 {
713 previousArtifact =
714 factory.createDependencyArtifact( currentProject.getGroupId(), currentProject.getArtifactId(), range,
715 currentProject.getPackaging(), null, Artifact.SCOPE_COMPILE );
716
717 if ( !previousArtifact.getVersionRange().isSelectedVersionKnown( previousArtifact ) )
718 {
719 getLog().debug( "Searching for versions in range: " + previousArtifact.getVersionRange() );
720 List<ArtifactVersion> availableVersions =
721 metadataSource.retrieveAvailableVersions( previousArtifact, localRepository,
722 currentProject.getRemoteArtifactRepositories() );
723 filterSnapshots( availableVersions );
724 ArtifactVersion version = range.matchVersion( availableVersions );
725 if ( version != null )
726 {
727 previousArtifact.selectVersion( version.toString() );
728 }
729 }
730
731 }
732 catch ( OverConstrainedVersionException e1 )
733 {
734 throw new MojoFailureException( "Invalid comparison version: " + e1.getMessage() );
735 }
736 catch ( ArtifactMetadataRetrievalException e11 )
737 {
738 throw new MojoExecutionException( "Error determining previous version: " + e11.getMessage(), e11 );
739 }
740
741 if ( previousArtifact.getVersion() == null )
742 {
743 getLog().info( "Unable to find a previous version of the project in the repository" );
744 }
745 else
746 {
747 getLog().debug( "Previous version: " + previousArtifact.getVersion() );
748 }
749
750 return previousArtifact;
751 }
752
753 private void filterSnapshots( List<ArtifactVersion> versions )
754 {
755 for ( Iterator<ArtifactVersion> versionIterator = versions.iterator(); versionIterator.hasNext(); )
756 {
757 if ( "SNAPSHOT".equals( versionIterator.next().getQualifier() ) )
758 {
759 versionIterator.remove();
760 }
761 }
762 }
763
764 private void fetchSources( File checkoutDir, MavenProject mavenProject )
765 throws MojoExecutionException
766 {
767 try
768 {
769 if ( forceCheckout && checkoutDir.exists() )
770 {
771 FileUtils.deleteDirectory( checkoutDir );
772 }
773
774 if ( checkoutDir.mkdirs() )
775 {
776
777 getLog().info( "Performing checkout to " + checkoutDir );
778
779 new ScmCommandExecutor( scmManager, getConnection( mavenProject ), getLog() ).checkout( checkoutDir.getPath() );
780 }
781 else
782 {
783 getLog().info( "Performing update to " + checkoutDir );
784
785 new ScmCommandExecutor( scmManager, getConnection( mavenProject ), getLog() ).update( checkoutDir.getPath() );
786 }
787 }
788 catch ( Exception ex )
789 {
790 throw new MojoExecutionException( "checkout failed.", ex );
791 }
792 }
793
794 private static void setCliProperty( String property, Properties properties )
795 {
796 String name;
797
798 String value;
799
800 int i = property.indexOf( "=" );
801
802 if ( i <= 0 )
803 {
804 name = property.trim();
805
806 value = "true";
807 }
808 else
809 {
810 name = property.substring( 0, i ).trim();
811
812 value = property.substring( i + 1 );
813 }
814
815 properties.setProperty( name, value );
816 }
817 }