001 package hirondelle.web4jtools.util; 002 003 import java.util.logging.*; 004 import javax.servlet.jsp.JspException; 005 import hirondelle.web4j.ui.tag.TagHelper; 006 import hirondelle.web4j.util.Util; 007 import hirondelle.web4jtools.codegenerator.feature.Feature; 008 import hirondelle.web4jtools.codegenerator.feature.FeatureAction; 009 010 import java.io.*; 011 import hirondelle.web4j.util.Consts; 012 import javax.servlet.ServletConfig; 013 import hirondelle.web4jtools.util.Ensure; 014 015 /** 016 * Echo the trimmed body, while also saving it as a file on the server as a side-effect. 017 * 018 * <P>Uses two settings in <tt>web.xml</tt> : 019 * <ul> 020 * <li><tt>BaseDirectoryForGeneratedFiles</tt> - the base or root directory for your classes. 021 * This code generator follows the 022 * <a href='http://www.web4j.com/UserGuide.jsp#DirectoryStructure'>package-by-feature</a> style 023 * recommended by WEB4J, in which all items related to a given feature are placed in a single directory: 024 * JSP, Action, Model, DAO, and .sql file. A value of <tt>'Disabled'</tt> for this setting will turn off 025 * all file generation. When enabled, the value has the form <tt>[project-root]/WEB-INF/classes/</tt>. 026 * <li><tt>CharacterSetForGeneratedFiles</tt> - controls the character encoding of generated files. 027 * </ul> 028 * 029 * <P>Example use case in a JSP : 030 * <PRE> 031 <w:saveToFile named='statements.sql'> 032 ...JSP content... 033 </w:saveToFile> 034 * </PRE> 035 * The exact location of the generated files depends on the package name. If the above snippet is 036 * for a feature having the package <tt>com.xyz.jet</tt>, then the generated file will be 037 * <P><tt>[project-root]/WEB-INF/classes/com/xyz/jet/statements.sql</tt> 038 */ 039 public final class SaveToFile extends TagHelper { 040 041 /** Read in configuration from <tt>web.xml</tt> */ 042 static public void readConfig(ServletConfig aConfig){ 043 fBASE_DIR = aConfig.getInitParameter(BASE_DIR); 044 fCHARSET = aConfig.getInitParameter(CHARSET); 045 Ensure.isPresentInWebXml(BASE_DIR, fBASE_DIR); 046 Ensure.isPresentInWebXml(CHARSET, fCHARSET); 047 } 048 049 /** Set the name of the emitted file. */ 050 public void setNamed(String aFileName){ 051 fFileName = aFileName; 052 } 053 054 @Override protected String getEmittedText(String aBody) throws JspException, IOException { 055 if( isEnabled() ) { 056 saveToFile(aBody.trim(), getOutputFileName()); 057 } 058 else { 059 fLogger.fine("Not saving to file, since disabled."); 060 } 061 return aBody; 062 } 063 064 /** 065 * Return <tt>true</tt> only if <tt>BaseDirectoryForGeneratedFiles</tt> (<tt>web.xml</tt>) is not 066 * set to <tt>'Disabled'</tt> (ignoring case). 067 */ 068 public static boolean isEnabled(){ 069 return ! DISABLED.equalsIgnoreCase(fBASE_DIR); 070 } 071 072 // PRIVATE // 073 private String fFileName; 074 075 private static final String BASE_DIR = "BaseDirectoryForGeneratedFiles"; 076 private static final String DISABLED = "Disabled"; 077 private static String fBASE_DIR; 078 079 private static final String CHARSET = "CharacterSetForGeneratedFiles"; 080 private static String fCHARSET; 081 082 private static final Logger fLogger = Util.getLogger(SaveToFile.class); 083 084 private String getOutputFileName() throws IOException { 085 String directory = getProjectRootForClasses() + getPackagePath(); 086 ensureDirectoryExists(directory); 087 ensureFileExists(); 088 String result = directory + fFileName; 089 fLogger.fine("Saving to file named : " + result); 090 return result; 091 } 092 093 private String getProjectRootForClasses(){ 094 return fBASE_DIR; 095 } 096 097 private String getPackagePath(){ 098 Feature feature = (Feature)getRequest().getSession().getAttribute(FeatureAction.FEATURE_KEY); 099 return addDirectorySeparators(feature.getPackageName()); 100 } 101 102 private String addDirectorySeparators(String aPackageName){ 103 return Util.replace(aPackageName, ".", Consts.FILE_SEPARATOR) + Consts.FILE_SEPARATOR; 104 } 105 106 /** Emit the text into the file. */ 107 private void saveToFile(String aBody, String aOutputFileName) throws IOException { 108 Writer out = null; 109 try { 110 FileOutputStream fos = new FileOutputStream(aOutputFileName); 111 out = new BufferedWriter(new OutputStreamWriter(fos, fCHARSET)); 112 out.write(aBody); 113 } 114 finally { 115 if ( out != null) out.close(); 116 } 117 } 118 119 private void ensureDirectoryExists(String aDirName){ 120 File dir = new File(aDirName); 121 dir.mkdirs(); 122 } 123 124 private void ensureFileExists() throws IOException { 125 File file = new File(fFileName); 126 file.createNewFile(); //does not create if already exists 127 } 128 }