001/* 002 * jDTAUS Core Resource Mojo 003 * Copyright (C) 2005 Christian Schulte 004 * <cs@schulte.it> 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License, or any later version. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 019 * 020 */ 021package org.jdtaus.mojo.resource; 022 023import java.io.File; 024import java.io.FileInputStream; 025import java.io.FileOutputStream; 026import java.io.FileWriter; 027import java.io.InputStream; 028import java.io.OutputStream; 029import java.io.OutputStreamWriter; 030import java.io.Writer; 031import java.text.DateFormat; 032import java.text.MessageFormat; 033import java.util.Date; 034import java.util.Iterator; 035import java.util.Map; 036import java.util.Properties; 037import java.util.ResourceBundle; 038import org.apache.maven.model.Resource; 039import org.apache.maven.plugin.AbstractMojo; 040import org.apache.maven.plugin.MojoExecutionException; 041import org.apache.maven.plugin.MojoFailureException; 042import org.apache.maven.project.MavenProject; 043import org.jdtaus.mojo.resource.model.Implementation; 044import org.jdtaus.mojo.resource.model.Message; 045import org.jdtaus.mojo.resource.model.ModelManager; 046import org.jdtaus.mojo.resource.model.Module; 047import org.jdtaus.mojo.resource.model.Text; 048import org.jdtaus.mojo.resource.util.BundleGenerator; 049 050/** 051 * Mojo to generate java resource accessor classes backed by java 052 * <code>ResourceBundle</code>s from a project's module descriptor. 053 * 054 * @goal java-resources 055 * @phase generate-sources 056 * @requiresDependencyResolution compile 057 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> 058 * @version $JDTAUS: JavaResourcesMojo.java 8641 2012-09-27 06:45:17Z schulte $ 059 */ 060public class JavaResourcesMojo extends AbstractMojo 061{ 062 //--JavaResourcesMojo------------------------------------------------------- 063 064 /** 065 * Currently executed <code>MavenProject</code>. 066 * 067 * @parameter expression="${project}" 068 * @required 069 */ 070 private MavenProject project; 071 072 /** 073 * The directory to generate sources to. 074 * 075 * @parameter expression="${project.build.directory}/generated-sources/java-resources" 076 */ 077 private File sourceDirectory; 078 079 /** 080 * The directory to generate resources to. 081 * 082 * @parameter expression="${project.build.directory}/generated-resources/java-resources" 083 */ 084 private File resourceDirectory; 085 086 /** 087 * The directory to use for storing hashes for already generated files. 088 * 089 * @parameter expression="${project.build.directory}/java-resources" 090 */ 091 private File buildDirectory; 092 093 /** 094 * Project module descriptor to control the mojo. 095 * @parameter expression="${javaResources.moduleDescriptor}" 096 * default-value="src/main/resources/META-INF/jdtaus/module.xml" 097 */ 098 private File moduleDescriptor; 099 100 /** 101 * The encoding to use for writing sources. 102 * @parameter expression="${project.build.sourceEncoding}" 103 */ 104 private String encoding; 105 106 /** 107 * The default language for generated bundles. 108 * @parameter expression="${javaResources.defaultLanguage}" 109 * default-value="en" 110 */ 111 private String defaultLanguage; 112 113 /** @component */ 114 private BundleGenerator generator; 115 116 /** @component */ 117 private ModelManager modelManager; 118 119 private MavenProject getProject() 120 { 121 return this.project; 122 } 123 124 private File getSourceDirectory() 125 { 126 return this.sourceDirectory; 127 } 128 129 private File getResourceDirectory() 130 { 131 return this.resourceDirectory; 132 } 133 134 private File getBuildDirectory() 135 { 136 return this.buildDirectory; 137 } 138 139 private BundleGenerator getBundleGenerator() 140 { 141 return this.generator; 142 } 143 144 private ModelManager getModelManager() 145 { 146 return this.modelManager; 147 } 148 149 private File getModuleDescriptor() 150 { 151 return this.moduleDescriptor; 152 } 153 154 private String getEncoding() 155 { 156 return this.encoding; 157 } 158 159 private String getDefaultLanguage() 160 { 161 return this.defaultLanguage; 162 } 163 164 public void execute() throws MojoExecutionException, MojoFailureException 165 { 166 if ( !this.getModuleDescriptor().exists() ) 167 { 168 throw new MojoExecutionException( 169 this.getMessage( "fileNotFound" ). 170 format( new Object[] 171 { 172 this.getModuleDescriptor().getAbsolutePath() 173 } ) ); 174 175 } 176 177 try 178 { 179 this.assertDirectoryExistence( this.getSourceDirectory() ); 180 this.assertDirectoryExistence( this.getResourceDirectory() ); 181 this.assertDirectoryExistence( this.getBuildDirectory() ); 182 183 this.getProject().addCompileSourceRoot( 184 this.getSourceDirectory().getAbsolutePath() ); 185 186 final Resource resource = new Resource(); 187 resource.setDirectory( this.getResourceDirectory(). 188 getAbsolutePath() ); 189 190 resource.setFiltering( false ); 191 192 this.getProject().addResource( resource ); 193 194 final Module module = this.getModelManager(). 195 getModule( this.getModuleDescriptor() ); 196 197 if ( module != null ) 198 { 199 this.assertValidTemplates( module ); 200 if ( module.getImplementations() != null ) 201 { 202 this.generateBundles( module ); 203 } 204 } 205 } 206 catch ( Exception e ) 207 { 208 throw new MojoExecutionException( e.getMessage(), e ); 209 } 210 } 211 212 private MessageFormat getMessage( final String key ) 213 { 214 if ( key == null ) 215 { 216 throw new NullPointerException( "key" ); 217 } 218 219 return new MessageFormat( 220 ResourceBundle.getBundle( JavaResourcesMojo.class.getName() ). 221 getString( key ) ); 222 223 } 224 225 private void assertDirectoryExistence( final File directory ) 226 throws MojoExecutionException 227 { 228 if ( !directory.exists() && !directory.mkdirs() ) 229 { 230 throw new MojoExecutionException( 231 this.getMessage( "cannotCreateDirectory" ). 232 format( new Object[] 233 { 234 directory.getAbsolutePath() 235 } ) ); 236 237 238 } 239 } 240 241 private void generateBundles( final Module module ) 242 throws Exception 243 { 244 final Properties bundleHashcodes = new Properties(); 245 final File propertiesFile = 246 new File( this.getBuildDirectory(), "bundles.properties" ); 247 248 if ( !propertiesFile.exists() ) 249 { 250 propertiesFile.createNewFile(); 251 } 252 253 final InputStream in = new FileInputStream( propertiesFile ); 254 bundleHashcodes.load( in ); 255 in.close(); 256 257 for ( Iterator it = module.getImplementations().getImplementation(). 258 iterator(); it.hasNext(); ) 259 { 260 final Implementation impl = (Implementation) it.next(); 261 if ( impl.getMessages() == null ) 262 { 263 continue; 264 } 265 266 final int bundleHash = this.getModelManager(). 267 getHashCode( module, impl ); 268 269 final String propertyHash = 270 bundleHashcodes.getProperty( impl.getIdentifier() ); 271 272 if ( propertyHash == null || 273 Integer.valueOf( propertyHash ).intValue() != bundleHash ) 274 { 275 bundleHashcodes.setProperty( impl.getIdentifier(), 276 Integer.toString( bundleHash ) ); 277 278 final String bundlePath = 279 ( this.getModelManager().getJavaPackageName( impl ) + 280 '.' + this.getModelManager().getJavaTypeName( impl ) ). 281 replace( '.', File.separatorChar ); 282 283 final File bundleFile = new File( this.getSourceDirectory(), 284 bundlePath + ".java" ); 285 286 this.assertDirectoryExistence( bundleFile.getParentFile() ); 287 288 final Writer writer = 289 this.getEncoding() == null 290 ? new FileWriter( bundleFile ) 291 : new OutputStreamWriter( new FileOutputStream( 292 bundleFile ), 293 this.getEncoding() ); 294 295 this.getLog().info( this.getMessage( "writingBundle" ). 296 format( new Object[] 297 { 298 bundleFile.getName() 299 } ) ); 300 301 this.getBundleGenerator().generateJava( module, impl, writer ); 302 303 writer.close(); 304 305 final Map bundleProperties = this.getModelManager(). 306 getBundleProperties( module, impl ); 307 308 for ( Iterator properties = bundleProperties.entrySet(). 309 iterator(); properties.hasNext(); ) 310 { 311 final Map.Entry entry = (Map.Entry) properties.next(); 312 final String language = (String) entry.getKey(); 313 final Properties p = (Properties) entry.getValue(); 314 final File file = new File( this.getResourceDirectory(), 315 bundlePath + "_" + language + 316 ".properties" ); 317 318 this.getLog().info( this.getMessage( "writingBundle" ). 319 format( new Object[] 320 { 321 file.getName() 322 } ) ); 323 324 this.assertDirectoryExistence( file.getParentFile() ); 325 326 final OutputStream out = new FileOutputStream( file ); 327 p.store( out, this.getProject().getName() ); 328 out.close(); 329 330 if ( this.getDefaultLanguage(). 331 equalsIgnoreCase( language ) ) 332 { 333 final File defaultFile = 334 new File( this.getResourceDirectory(), 335 bundlePath + ".properties" ); 336 337 this.assertDirectoryExistence( 338 defaultFile.getParentFile() ); 339 340 this.getLog().info( this.getMessage( "writingBundle" ). 341 format( new Object[] 342 { 343 defaultFile.getName() 344 } ) ); 345 346 final OutputStream defaultOut = 347 new FileOutputStream( defaultFile ); 348 349 p.store( defaultOut, this.getProject().getName() ); 350 defaultOut.close(); 351 } 352 } 353 } 354 } 355 356 final OutputStream out = new FileOutputStream( propertiesFile ); 357 bundleHashcodes.store( out, this.getClass().getName() + ": " + 358 DateFormat.getDateTimeInstance(). 359 format( new Date() ) ); 360 361 out.close(); 362 } 363 364 private void assertValidTemplates( final Module module ) 365 throws MojoExecutionException 366 { 367 if ( module.getImplementations() != null ) 368 { 369 for ( Iterator it = module.getImplementations().getImplementation(). 370 iterator(); it.hasNext(); ) 371 { 372 final Implementation impl = (Implementation) it.next(); 373 if ( impl.getMessages() == null ) 374 { 375 continue; 376 } 377 378 for ( Iterator m = impl.getMessages().getMessage().iterator(); 379 m.hasNext(); ) 380 { 381 this.assertValidMessage( (Message) m.next() ); 382 } 383 } 384 } 385 386 if ( module.getMessages() != null ) 387 { 388 for ( Iterator it = module.getMessages().getMessage().iterator(); 389 it.hasNext(); ) 390 { 391 this.assertValidMessage( (Message) it.next() ); 392 } 393 } 394 } 395 396 private void assertValidMessage( final Message message ) 397 throws MojoExecutionException 398 { 399 if ( message.getTemplate() != null ) 400 { 401 for ( Iterator it = message.getTemplate().getText().iterator(); 402 it.hasNext(); ) 403 { 404 final Text text = (Text) it.next(); 405 try 406 { 407 new MessageFormat( text.getValue() ); 408 } 409 catch ( IllegalArgumentException e ) 410 { 411 final MessageFormat fmt = 412 this.getMessage( "illegalTemplate" ); 413 414 throw new MojoExecutionException( fmt.format( new Object[] 415 { 416 text.getValue(), 417 message.getName(), 418 e.getMessage() 419 } ), e ); 420 421 } 422 } 423 } 424 } 425 426 //-------------------------------------------------------JavaResourcesMojo-- 427}