/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.codehaus.mojo.cis.core; import java.io.File; import java.io.FilenameFilter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; /** * The HTML generator is used to convert the XML layout files into * HTML files. It is invoked after creating the web application * directory. In particular, it creates its own classpath by using * files in the WEB-INF/lib directory. */ public class HTMLGeneratorBean extends AbstractCisBean { private boolean htmlDirChecked, xmlTargetDirChecked, logDirChecked; private boolean accessPathDirChecked; private Object htmlGenerator; private Method htmlGeneratorMethod; private File xmlDir, xmlTargetDir, htmlDir, logDir, accessPathDir; /** * Returns the directory containing the XML layouts. Basically, * this is the source directory. */ public File getXmlDir() { return xmlDir; } /** * Sets the directory containing the XML layouts. Basically, * this is the source directory. */ public void setXmlDir( File pXmlDir ) { xmlDir = pXmlDir; } /** * Returns the target directory for XML layouts. If present, this * is used as the target directory for uptodate checks. Otherwise, * the {@link #getHtmlDir() HTML directory} is used. */ public File getXmlTargetDir() { return xmlTargetDir; } /** * Sets the target directory for XML layouts. If present, this * is used as the target directory for uptodate checks. Otherwise, * the {@link #getHtmlDir() HTML directory} is used. */ public void setXmlTargetDir( File pXmlTargetDir ) { xmlTargetDir = pXmlTargetDir; } /** * Returns the directory containing the generated HTML files. * Basically, this is the target directory. */ public File getHtmlDir() { return htmlDir; } /** * Sets the directory containing the generated HTML files. * Basically, this is the target directory. */ public void setHtmlDir( File pHtmlDir ) { htmlDir = pHtmlDir; } /** * Returns the directory containing the log files. */ public File getLogDir() { return logDir; } /** * Sets the directory containing the log files. */ public void setLogDir( File pLogDir ) { logDir = pLogDir; } /** * Returns the directory containing the accesspath files. */ public File getAccessPathDir() { return accessPathDir; } /** * Sets the directory containing the accesspath files. */ public void setAccessPathDir( File pAccessDir ) { accessPathDir = pAccessDir; } private File makeFileName( File pXmlFile, File pTargetDir, String pExtension ) { final String xmlName = pXmlFile.getName(); final String newName = xmlName.substring( 0, xmlName.length() - ".xml".length() ) + pExtension; return new File( pTargetDir, newName ); } /** * Prepares the settings for accessing the CIS home directory. */ private Object prepareHtmlGenerator( File pLogDir ) throws CisCoreException { if ( htmlGenerator != null ) { return htmlGenerator; } File cisHomeDirectory = checkCisHomeDir(); System.setProperty( "cis.home", cisHomeDirectory.getPath() ); final File webInfClassesDirectory = new File( new File( cisHomeDirectory, "WEB-INF" ), "classes" ); final List urls = new ArrayList(); if ( webInfClassesDirectory.isDirectory() ) { try { urls.add( webInfClassesDirectory.toURI().toURL() ); } catch ( MalformedURLException e ) { throw new CisCoreErrorMessage( e ); } } final File webInfLibDirectory = new File( new File( cisHomeDirectory, "WEB-INF" ), "lib" ); if ( !webInfLibDirectory.isDirectory() ) { throw new CisCoreErrorMessage( "The configured CIS home directory " + cisHomeDirectory + " does not contain a subdirectory WEB-INF/lib." ); } final File[] files = webInfLibDirectory.listFiles( new FilenameFilter() { public boolean accept( File pDirectory, String pFileName ) { return pFileName.endsWith( ".jar" ); } } ); Arrays.sort( files, new Comparator() { public int compare( Object pFile1, Object pFile2 ) { final String s1 = ( (File) pFile1 ).getName(); final String s2 = ( (File) pFile2 ).getName(); return s1.compareToIgnoreCase( s2 ); } } ); for ( int i = 0; i < files.length; i++ ) { final File f = files[ i ]; if ( f.isFile() ) { try { urls.add( f.toURI().toURL() ); } catch ( MalformedURLException e ) { throw new CisCoreErrorMessage( e ); } } } final URL[] urlArray = (URL[]) urls.toArray( new URL[ urls.size() ] ); final ClassLoader cl = new URLClassLoader( urlArray, ClassLoader.getSystemClassLoader() ); final CISInitializer cisInitializer = new CISInitializer(); cisInitializer.setCisHomeDir( cisHomeDirectory ); cisInitializer.setLogDir( pLogDir ); cisInitializer.setCisUtils( getCisUtils() ); cisInitializer.setTempDir( getCisUtils().getTempDir() ); cisInitializer.init( cl ); final String className = "com.softwareag.cis.gui.generate.HTMLGenerator"; System.setProperty( className + ".running", "true" ); final Class clazz; try { clazz = cl.loadClass( className ); } catch ( ClassNotFoundException e ) { throw new CisCoreException( "Failed to load class " + className + ": " + e.getMessage(), e ); } final Object o; try { o = clazz.newInstance(); } catch ( InstantiationException e ) { throw new CisCoreException( "Failed to instantiate class " + className + ": " + e.getMessage(), e ); } catch ( IllegalAccessException e ) { throw new CisCoreException( "Illegal access to class " + className + ": " + e.getMessage(), e ); } final Method m; try { final Class[] parameterTypes = new Class[] { String.class, String.class, String.class, String.class }; m = clazz.getMethod( "generateHTMLFile", parameterTypes ); } catch ( NoSuchMethodException e ) { throw new CisCoreException( "The class " + className + " contains no method generateHTMLFile(String,String,String,String)." , e ); } htmlGenerator = o; htmlGeneratorMethod = m; return htmlGenerator; } /** * Invokes the HTML generator to convert the given layout into the * given HTML file. */ private void runHtmlGenerator( File pXmlFile, File pHtmlFile, File pLogFile, File pAccessPathFile ) throws CisCoreException { final Object[] args = new Object[] { pXmlFile.getPath(), pHtmlFile.getPath(), pLogFile.getPath(), pAccessPathFile.getPath() }; try { htmlGeneratorMethod.invoke( htmlGenerator, args ); } catch ( IllegalAccessException e ) { throw new CisCoreException( "Illegal access to method " + htmlGeneratorMethod.getName() + " of class " + htmlGenerator.getClass().getName() + ": " + e.getMessage(), e ); } catch ( IllegalArgumentException e ) { throw new CisCoreException( "Illegal argument for method " + htmlGeneratorMethod.getName() + " of class " + htmlGenerator.getClass().getName() + ": " + e.getMessage(), e ); } catch ( InvocationTargetException e ) { final Throwable t = e.getTargetException(); throw new CisCoreException( "Failed to invoke method " + htmlGeneratorMethod.getName() + " of class " + htmlGenerator.getClass().getName() + ": " + t.getMessage(), t ); } } /** * Called to generate a single HTML file from its corresponding * XML file. */ private boolean generate( File pXmlFile ) throws CisCoreException { final CisUtils.Resource sourceResource = new DefaultResource( pXmlFile ); final File xmlTargetDirectory = checkXmlTargetDirectory(); final File htmlDirectory = checkHtmlDirectory(); final CisUtils utils = getCisUtils(); final File htmlFile = makeFileName( pXmlFile, htmlDirectory, ".html" ); final File xmlTargetFile = xmlTargetDirectory == null ? null : new File( xmlTargetDirectory, pXmlFile.getName() ); final File targetFile = xmlTargetFile == null ? htmlFile : xmlTargetFile; final CisUtils.Resource targetResource = new DefaultResource( targetFile ); if ( utils.isUpToDate( sourceResource, targetResource ) ) { utils.debug( "File " + htmlFile + " is uptodate." ); return false; } utils.debug( "HTML file " + htmlFile + " is being generated." ); final File accessPathDirectory = checkAccessPathDirectory(); final File accessPathFile = makeFileName( pXmlFile, accessPathDirectory, ".access" ); final File logDirectory = checkLogDirectory(); final File logFile = makeFileName( pXmlFile, logDirectory, ".log" ); prepareHtmlGenerator( logDirectory ); boolean success = false; try { if ( xmlTargetFile != null ) { utils.copy( pXmlFile, xmlTargetFile ); } runHtmlGenerator( pXmlFile, htmlFile, logFile, accessPathFile ); success = true; } finally { if ( !success && xmlTargetFile != null ) { /* Remove the XML target file, so that the generator will run again * the next time. */ xmlTargetFile.delete(); } } return true; } private File checkAccessPathDirectory() throws CisCoreErrorMessage, CisCoreException { final File accessPathDirectory = getAccessPathDir(); if ( !accessPathDirChecked ) { if ( accessPathDirectory == null ) { throw new CisCoreErrorMessage( "The access path directory is not set." ); } if ( !accessPathDirectory.isDirectory() && !accessPathDirectory.mkdirs() ) { throw new CisCoreException( "Unable to create the configured access path directory " + accessPathDirectory.getPath() ); } accessPathDirChecked = true; } return accessPathDirectory; } private File checkLogDirectory() throws CisCoreErrorMessage, CisCoreException { final File logDirectory = getLogDir(); if ( !logDirChecked ) { if ( logDirectory == null ) { throw new CisCoreErrorMessage( "The log directory is not set." ); } if ( !logDirectory.isDirectory() && !logDirectory.mkdirs() ) { throw new CisCoreException( "Unable to create the configured log directory " + logDirectory.getPath() ); } logDirChecked = true; } return logDirectory; } private File checkXmlTargetDirectory() throws CisCoreException { final File xmlTargetDirectory = getXmlTargetDir(); if ( !xmlTargetDirChecked ) { if ( xmlTargetDirectory != null && !xmlTargetDirectory.isDirectory() && !xmlTargetDirectory.mkdirs() ) { throw new CisCoreException( "Failed to create XML target directory " + xmlTargetDirectory.getPath() ); } xmlTargetDirChecked = true; } return xmlTargetDirectory; } private File checkHtmlDirectory() throws CisCoreException { final File htmlDirectory = getHtmlDir(); if ( !htmlDirChecked ) { if ( htmlDirectory == null ) { throw new CisCoreErrorMessage( "The HTML directory is not set." ); } if ( !htmlDirectory.isDirectory() && !htmlDirectory.mkdirs() ) { throw new CisCoreException( "Unable to create the configured HTML directory " + htmlDirectory.getPath() ); } htmlDirChecked = true; } return htmlDirectory; } /** * Called to scan the {@link #setXmlDir(File)} for XML * layouts and generating the HTML layouts. */ public void execute() throws CisCoreException { final File xmlDirectory = getXmlDir(); if ( xmlDirectory == null ) { throw new CisCoreErrorMessage( "The XML directory is not set." ); } if ( !xmlDirectory.isDirectory() ) { throw new CisCoreErrorMessage( "The configured XML directory " + xmlDirectory.getPath() + " does not exist or is no directory." ); } final File[] files = xmlDirectory.listFiles( new FilenameFilter() { public boolean accept( File pDir, String pName ) { return pName.endsWith( ".xml" ); } } ); int numGeneratedFiles = 0; int numUpToDateFiles = 0; for ( int i = 0; i < files.length; i++ ) { if ( generate( files[i] ) ) { ++numGeneratedFiles; } else { ++numUpToDateFiles; } } logResult( numGeneratedFiles, numUpToDateFiles ); } private void logResult( int numGeneratedFiles, int numUpToDateFiles ) { if ( numGeneratedFiles == 0 ) { getCisUtils().debug( "All files are uptodate." ); } else { final StringBuffer sb = new StringBuffer(); sb.append("Generated "); sb.append(String.valueOf(numGeneratedFiles)); sb.append(" HTML "); if (numGeneratedFiles == 1) { sb.append("file"); } else { sb.append("files"); } sb.append(", "); sb.append(String.valueOf(numUpToDateFiles)); if (numUpToDateFiles == 1) { sb.append(" file has been uptodate."); } else { sb.append(" files have been uptodate."); } getCisUtils().info( sb.toString() ); } } }