ResourceFileProcessor.java
- /*
- * Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * o Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * o Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $JOMC: ResourceFileProcessor.java 5043 2015-05-27 07:03:39Z schulte $
- *
- */
- package org.jomc.tools;
- import java.io.ByteArrayOutputStream;
- import java.io.Closeable;
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.nio.ByteBuffer;
- import java.nio.channels.FileChannel;
- import java.nio.channels.FileLock;
- import java.text.MessageFormat;
- import java.util.HashMap;
- import java.util.Locale;
- import java.util.Map;
- import java.util.Properties;
- import java.util.ResourceBundle;
- import java.util.logging.Level;
- import org.apache.velocity.VelocityContext;
- import org.jomc.model.Implementation;
- import org.jomc.model.JavaTypeName;
- import org.jomc.model.Message;
- import org.jomc.model.Messages;
- import org.jomc.model.ModelObjectException;
- import org.jomc.model.Module;
- import org.jomc.model.Specification;
- import org.jomc.model.Text;
- /**
- * Processes resource files.
- *
- * <p>
- * <b>Use Cases:</b><br/><ul>
- * <li>{@link #writeResourceBundleResourceFiles(File) }</li>
- * <li>{@link #writeResourceBundleResourceFiles(Module, File) }</li>
- * <li>{@link #writeResourceBundleResourceFiles(Specification, File) }</li>
- * <li>{@link #writeResourceBundleResourceFiles(Implementation, File) }</li>
- * </ul></p>
- *
- * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
- * @version $JOMC: ResourceFileProcessor.java 5043 2015-05-27 07:03:39Z schulte $
- *
- * @see #getModules()
- */
- public class ResourceFileProcessor extends JomcTool
- {
- /**
- * The language of the default language properties file of generated resource bundle resources.
- */
- private Locale resourceBundleDefaultLocale;
- /**
- * Creates a new {@code ResourceFileProcessor} instance.
- */
- public ResourceFileProcessor()
- {
- super();
- }
- /**
- * Creates a new {@code ResourceFileProcessor} instance taking a {@code ResourceFileProcessor} instance to
- * initialize the instance with.
- *
- * @param tool The instance to initialize the new instance with.
- *
- * @throws NullPointerException if {@code tool} is {@code null}.
- * @throws IOException if copying {@code tool} fails.
- */
- public ResourceFileProcessor( final ResourceFileProcessor tool ) throws IOException
- {
- super( tool );
- this.resourceBundleDefaultLocale = tool.resourceBundleDefaultLocale;
- }
- /**
- * Gets the language of the default language properties file of generated resource bundle resource files.
- *
- * @return The language of the default language properties file of generated resource bundle resource files.
- *
- * @see #setResourceBundleDefaultLocale(java.util.Locale)
- */
- public final Locale getResourceBundleDefaultLocale()
- {
- if ( this.resourceBundleDefaultLocale == null )
- {
- this.resourceBundleDefaultLocale = Locale.ENGLISH;
- if ( this.isLoggable( Level.CONFIG ) )
- {
- this.log( Level.CONFIG, getMessage( "defaultResourceBundleDefaultLocale",
- this.resourceBundleDefaultLocale ), null );
- }
- }
- return this.resourceBundleDefaultLocale;
- }
- /**
- * Sets the language of the default language properties file of generated resource bundle resource files.
- *
- * @param value The language of the default language properties file of generated resource bundle resource files.
- *
- * @see #getResourceBundleDefaultLocale()
- */
- public final void setResourceBundleDefaultLocale( final Locale value )
- {
- this.resourceBundleDefaultLocale = value;
- }
- /**
- * Writes resource bundle resource files of the modules of the instance to a given directory.
- *
- * @param resourcesDirectory The directory to write resource bundle resource files to.
- *
- * @throws NullPointerException if {@code resourcesDirectory} is {@code null}.
- * @throws IOException if writing resource bundle resource files fails.
- * @throws ModelObjectException if compiling the name of a referenced type fails.
- *
- * @see #writeResourceBundleResourceFiles(org.jomc.model.Module, java.io.File)
- */
- public void writeResourceBundleResourceFiles( final File resourcesDirectory )
- throws IOException, ModelObjectException
- {
- if ( resourcesDirectory == null )
- {
- throw new NullPointerException( "resourcesDirectory" );
- }
- if ( this.getModules() != null )
- {
- for ( int i = 0, s0 = this.getModules().getModule().size(); i < s0; i++ )
- {
- this.writeResourceBundleResourceFiles( this.getModules().getModule().get( i ), resourcesDirectory );
- }
- }
- else if ( this.isLoggable( Level.WARNING ) )
- {
- this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
- }
- }
- /**
- * Writes resource bundle resource files of a given module from the modules of the instance to a given directory.
- *
- * @param module The module to process.
- * @param resourcesDirectory The directory to write resource bundle resource files to.
- *
- * @throws NullPointerException if {@code module} or {@code resourcesDirectory} is {@code null}.
- * @throws IOException if writing resource bundle resource files fails.
- * @throws ModelObjectException if compiling the name of a referenced type fails.
- *
- * @see #writeResourceBundleResourceFiles(org.jomc.model.Specification, java.io.File)
- * @see #writeResourceBundleResourceFiles(org.jomc.model.Implementation, java.io.File)
- */
- public void writeResourceBundleResourceFiles( final Module module, final File resourcesDirectory )
- throws IOException, ModelObjectException
- {
- if ( module == null )
- {
- throw new NullPointerException( "module" );
- }
- if ( resourcesDirectory == null )
- {
- throw new NullPointerException( "resourcesDirectory" );
- }
- if ( this.getModules() != null && this.getModules().getModule( module.getName() ) != null )
- {
- if ( module.getSpecifications() != null )
- {
- for ( int i = 0, s0 = module.getSpecifications().getSpecification().size(); i < s0; i++ )
- {
- this.writeResourceBundleResourceFiles( module.getSpecifications().getSpecification().get( i ),
- resourcesDirectory );
- }
- }
- if ( module.getImplementations() != null )
- {
- for ( int i = 0, s0 = module.getImplementations().getImplementation().size(); i < s0; i++ )
- {
- this.writeResourceBundleResourceFiles( module.getImplementations().getImplementation().get( i ),
- resourcesDirectory );
- }
- }
- }
- else if ( this.isLoggable( Level.WARNING ) )
- {
- this.log( Level.WARNING, getMessage( "moduleNotFound", module.getName() ), null );
- }
- }
- /**
- * Writes resource bundle resource files of a given specification from the modules of the instance to a directory.
- *
- * @param specification The specification to process.
- * @param resourcesDirectory The directory to write resource bundle resource files to.
- *
- * @throws NullPointerException if {@code specification} or {@code resourcesDirectory} is {@code null}.
- * @throws IOException if writing resource bundle resource files fails.
- * @throws ModelObjectException if compiling the name of the type referenced by the specification fails.
- *
- * @see #getResourceBundleResources(org.jomc.model.Specification)
- */
- public void writeResourceBundleResourceFiles( final Specification specification, final File resourcesDirectory )
- throws IOException, ModelObjectException
- {
- if ( specification == null )
- {
- throw new NullPointerException( "implementation" );
- }
- if ( resourcesDirectory == null )
- {
- throw new NullPointerException( "resourcesDirectory" );
- }
- if ( this.getModules() != null
- && this.getModules().getSpecification( specification.getIdentifier() ) != null )
- {
- if ( specification.isClassDeclaration() )
- {
- if ( !resourcesDirectory.isDirectory() )
- {
- throw new IOException( getMessage( "directoryNotFound", resourcesDirectory.getAbsolutePath() ) );
- }
- this.assertValidTemplates( specification );
- final JavaTypeName javaTypeName = specification.getJavaTypeName();
- if ( javaTypeName != null )
- {
- final String bundlePath = javaTypeName.getQualifiedName().replace( '.', File.separatorChar );
- this.writeResourceBundleResourceFiles(
- this.getResourceBundleResources( specification ), resourcesDirectory, bundlePath );
- }
- }
- }
- else if ( this.isLoggable( Level.WARNING ) )
- {
- this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
- }
- }
- /**
- * Writes resource bundle resource files of a given implementation from the modules of the instance to a directory.
- *
- * @param implementation The implementation to process.
- * @param resourcesDirectory The directory to write resource bundle resource files to.
- *
- * @throws NullPointerException if {@code implementation} or {@code resourcesDirectory} is {@code null}.
- * @throws IOException if writing resource bundle resource files fails.
- * @throws ModelObjectException if compiling the name of the type referenced by the implementation fails.
- *
- * @see #getResourceBundleResources(org.jomc.model.Implementation)
- */
- public void writeResourceBundleResourceFiles( final Implementation implementation, final File resourcesDirectory )
- throws IOException, ModelObjectException
- {
- if ( implementation == null )
- {
- throw new NullPointerException( "implementation" );
- }
- if ( resourcesDirectory == null )
- {
- throw new NullPointerException( "resourcesDirectory" );
- }
- if ( this.getModules() != null
- && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
- {
- if ( implementation.isClassDeclaration() )
- {
- if ( !resourcesDirectory.isDirectory() )
- {
- throw new IOException( getMessage( "directoryNotFound", resourcesDirectory.getAbsolutePath() ) );
- }
- this.assertValidTemplates( implementation );
- final JavaTypeName javaTypeName = implementation.getJavaTypeName();
- if ( javaTypeName != null )
- {
- final String bundlePath = javaTypeName.getQualifiedName().replace( '.', File.separatorChar );
- this.writeResourceBundleResourceFiles(
- this.getResourceBundleResources( implementation ), resourcesDirectory, bundlePath );
- }
- }
- }
- else if ( this.isLoggable( Level.WARNING ) )
- {
- this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
- }
- }
- /**
- * Gets resource bundle properties resources of a given specification.
- *
- * @param specification The specification to get resource bundle properties resources of.
- *
- * @return Resource bundle properties resources of {@code specification} or {@code null}, if no model objects are
- * found.
- *
- * @throws NullPointerException if {@code specification} is {@code null}.
- * @throws IOException if getting the resource bundle properties resources fails.
- */
- public Map<Locale, Properties> getResourceBundleResources( final Specification specification )
- throws IOException
- {
- if ( specification == null )
- {
- throw new NullPointerException( "specification" );
- }
- Map<Locale, Properties> properties = null;
- if ( this.getModules() != null
- && this.getModules().getSpecification( specification.getIdentifier() ) != null )
- {
- properties = new HashMap<Locale, Properties>();
- }
- else if ( this.isLoggable( Level.WARNING ) )
- {
- this.log( Level.WARNING, getMessage( "specificationNotFound", specification.getIdentifier() ), null );
- }
- return properties;
- }
- /**
- * Gets resource bundle properties resources of a given implementation.
- *
- * @param implementation The implementation to get resource bundle properties resources of.
- *
- * @return Resource bundle properties resources of {@code implementation} or {@code null}, if no model objects are
- * found.
- *
- * @throws NullPointerException if {@code implementation} is {@code null}.
- * @throws IOException if getting the resource bundle properties resources fails.
- */
- public Map<Locale, Properties> getResourceBundleResources( final Implementation implementation )
- throws IOException
- {
- if ( implementation == null )
- {
- throw new NullPointerException( "implementation" );
- }
- Map<Locale, Properties> properties = null;
- if ( this.getModules() != null
- && this.getModules().getImplementation( implementation.getIdentifier() ) != null )
- {
- properties = new HashMap<Locale, java.util.Properties>( 10 );
- final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
- if ( messages != null )
- {
- for ( int i = 0, s0 = messages.getMessage().size(); i < s0; i++ )
- {
- final Message message = messages.getMessage().get( i );
- if ( message.getTemplate() != null )
- {
- for ( int j = 0, s1 = message.getTemplate().getText().size(); j < s1; j++ )
- {
- final Text text = message.getTemplate().getText().get( j );
- final Locale locale = new Locale( text.getLanguage().toLowerCase() );
- Properties bundleProperties = properties.get( locale );
- if ( bundleProperties == null )
- {
- bundleProperties = new Properties();
- properties.put( locale, bundleProperties );
- }
- bundleProperties.setProperty( message.getName(), text.getValue() );
- }
- }
- }
- }
- }
- else if ( this.isLoggable( Level.WARNING ) )
- {
- this.log( Level.WARNING, getMessage( "implementationNotFound", implementation.getIdentifier() ), null );
- }
- return properties;
- }
- private void writeResourceBundleResourceFiles( final Map<Locale, Properties> resources,
- final File resourcesDirectory, final String bundlePath )
- throws IOException
- {
- if ( resources == null )
- {
- throw new NullPointerException( "resources" );
- }
- if ( resourcesDirectory == null )
- {
- throw new NullPointerException( "resourcesDirectory" );
- }
- if ( bundlePath == null )
- {
- throw new NullPointerException( "bundlePath" );
- }
- Properties defProperties = null;
- Properties fallbackProperties = null;
- final VelocityContext ctx = this.getVelocityContext();
- final String toolName = ctx.get( "toolName" ).toString();
- final String toolVersion = ctx.get( "toolVersion" ).toString();
- final String toolUrl = ctx.get( "toolUrl" ).toString();
- for ( final Map.Entry<Locale, Properties> e : resources.entrySet() )
- {
- final String language = e.getKey().getLanguage().toLowerCase();
- final Properties p = e.getValue();
- final File file = new File( resourcesDirectory, bundlePath + "_" + language + ".properties" );
- if ( this.getResourceBundleDefaultLocale().getLanguage().equalsIgnoreCase( language ) )
- {
- defProperties = p;
- }
- fallbackProperties = p;
- if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
- {
- throw new IOException( getMessage( "failedCreatingDirectory",
- file.getParentFile().getAbsolutePath() ) );
- }
- if ( this.isLoggable( Level.INFO ) )
- {
- this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
- }
- this.writePropertiesFile( p, toolName + ' ' + toolVersion + " - See " + toolUrl, file );
- }
- if ( defProperties == null )
- {
- defProperties = fallbackProperties;
- }
- if ( defProperties != null )
- {
- final File file = new File( resourcesDirectory, bundlePath + ".properties" );
- if ( !file.getParentFile().exists() && !file.getParentFile().mkdirs() )
- {
- throw new IOException( getMessage( "failedCreatingDirectory",
- file.getParentFile().getAbsolutePath() ) );
- }
- if ( this.isLoggable( Level.INFO ) )
- {
- this.log( Level.INFO, getMessage( "writing", file.getCanonicalPath() ), null );
- }
- this.writePropertiesFile( defProperties, toolName + ' ' + toolVersion + " - See " + toolUrl, file );
- }
- }
- private void assertValidTemplates( final Specification specification )
- {
- if ( specification == null )
- {
- throw new NullPointerException( "specification" );
- }
- }
- private void assertValidTemplates( final Implementation implementation )
- {
- if ( implementation == null )
- {
- throw new NullPointerException( "implementation" );
- }
- final Messages messages = this.getModules().getMessages( implementation.getIdentifier() );
- if ( messages != null )
- {
- for ( int i = messages.getMessage().size() - 1; i >= 0; i-- )
- {
- final Message m = messages.getMessage().get( i );
- if ( m.getTemplate() != null )
- {
- for ( int j = m.getTemplate().getText().size() - 1; j >= 0; j-- )
- {
- new MessageFormat( m.getTemplate().getText().get( j ).getValue() );
- }
- }
- }
- }
- }
- private void writePropertiesFile( final Properties properties, final String comments, final File propertiesFile )
- throws IOException
- {
- RandomAccessFile randomAccessFile = null;
- FileChannel fileChannel = null;
- FileLock fileLock = null;
- boolean suppressExceptionOnClose = true;
- final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
- properties.store( byteStream, comments );
- byteStream.close();
- final byte[] bytes = byteStream.toByteArray();
- try
- {
- randomAccessFile = new RandomAccessFile( propertiesFile, "rw" );
- fileChannel = randomAccessFile.getChannel();
- fileLock = fileChannel.lock();
- fileChannel.truncate( bytes.length );
- fileChannel.position( 0L );
- fileChannel.write( ByteBuffer.wrap( bytes ) );
- fileChannel.force( true );
- suppressExceptionOnClose = false;
- }
- finally
- {
- this.releaseAndClose( fileLock, fileChannel, randomAccessFile, suppressExceptionOnClose );
- }
- }
- private void releaseAndClose( final FileLock fileLock, final FileChannel fileChannel,
- final Closeable closeable, final boolean suppressExceptions )
- throws IOException
- {
- try
- {
- if ( fileLock != null )
- {
- fileLock.release();
- }
- }
- catch ( final IOException e )
- {
- if ( suppressExceptions )
- {
- this.log( Level.SEVERE, null, e );
- }
- else
- {
- throw e;
- }
- }
- finally
- {
- try
- {
- if ( fileChannel != null )
- {
- fileChannel.close();
- }
- }
- catch ( final IOException e )
- {
- if ( suppressExceptions )
- {
- this.log( Level.SEVERE, null, e );
- }
- else
- {
- throw e;
- }
- }
- finally
- {
- try
- {
- if ( closeable != null )
- {
- closeable.close();
- }
- }
- catch ( final IOException e )
- {
- if ( suppressExceptions )
- {
- this.log( Level.SEVERE, null, e );
- }
- else
- {
- throw e;
- }
- }
- }
- }
- }
- private static String getMessage( final String key, final Object... arguments )
- {
- if ( key == null )
- {
- throw new NullPointerException( "key" );
- }
- return MessageFormat.format( ResourceBundle.getBundle(
- ResourceFileProcessor.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
- }
- }