/*
* This software and supporting documentation were developed by
*
* Siemens Corporate Technology
* Competence Center Knowledge Management and Business Transformation
* D-81730 Munich, Germany
*
* Authors (representing a really great team ;-) )
* Stefan B. Augustin, Thorbj�rn Hansen, Manfred Langen
*
* This software is Open Source under GNU General Public License (GPL).
* Read the text of this license in LICENSE.TXT
* or look at www.opensource.org/licenses/
*
* Once more we emphasize, that:
* THIS SOFTWARE IS MADE AVAILABLE, AS IS, WITHOUT ANY WARRANTY
* REGARDING THE SOFTWARE, ITS PERFORMANCE OR
* FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
* ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
* PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
*
*/
// PropertiesProcessor
// ************ package ******************************************************
package KFM.preprocessor;
// ************ imports ******************************************************
import KFM.HTML.HtmlLoader2;
import java.util.*;
import java.io.*;
import KFM.DirNavigator.*;
import KFM.File.FileUtils;
import KFM.Converter;
/** The AbstractPreprocessor class is the base class for all preprocessors.
* <p> It provides basic functionality for the process of processing jsp-files.
* Usage:<br>
* If you want to write a new Preprocessor, subclass from AbstractPreprocessor and
* provide your own functionality by implementing the abstract methods.<br>
* If you don't want to traverse recursively, call the method setRecursiveMode with
* 'false'. The main method is 'traverse', calling this method will do the whole work for you.
*
*
* @see KFM.preprocessor.PropertiesProcessor
* @see Template-Pattern
*/
public abstract class AbstractPreprocessor implements FileWorker
{
// ************ attributes ******************************************************
private static boolean mTomcat = true;
private String mUrl = null; //url to the jsp file
private String cAlias = null; //the alias of the directory for the tomcat engine
private String cAliasDirectory = null; //config subdirectory
public final static String cSeparator = "/"; //file separator
public final static String cHttpParamMarker = "-Param"; //the prefix of an command line argument that
//indicates an http parameter
private boolean mTraverseRecursively = true; //indicates if traversing is done recursively
private boolean mCommentsOn = false; // indicates if the preprocessed files should have the comments included or not
//or only for the current directory
// ************ constants concerning file paths and aliases *************************
// Note: Think about placing them into config file !!!
private static File cTempDir;
public static final String cFilter = ".jsp";
protected int mErrors = 0;
// contains mapping "original file name" -> (File) "temporary file"
private Hashtable mTempFileHash = new Hashtable();
/**
* Constructor.
* @param aServerName the name of the server the tomcat engine runs on
* @param aServerPort the port number of the tomcat engine
* @param aTomcatAlias the alias of the current directory of the tomcat engine
* @param the directory name the tomcat alias refers to.
*/
public AbstractPreprocessor(
String aServerName,
String aServerPort,
String aTomcatAlias,
String aAliasDirectory,
File aTempDir)
{
cAlias = aTomcatAlias;
cAliasDirectory = aAliasDirectory;
mUrl = "http://" + aServerName + ":" + aServerPort;
cTempDir = aTempDir;
}
// ************ abstract methods ******************************************************
/**
* Provides the http parameter in properties format the jsp files needs.
*/
protected abstract Properties getHttpParams();
/**
* Implementing this method gives the user the possibility to create
* his own functionality of computing the path of the new file.
*/
protected abstract String computeNewFilePath(
File aFile);
/**
* Implementing this method provides a way of filtering the content of the preprocessed file.<br>
* Here you are given the possibility of changing the file's content.
*
* @param aContent the file's content
* @return the filtered file's content
*/
protected abstract String filterContent(
String aContent);
// ************ protected methods ******************************************************
/**
* Returns the tomcat alias of the current directory.
*/
protected String getTomcatAlias()
{
return cAlias;
}
/**
* Returns the directory name the tomcat alias refers to.
*/
protected String getAliasDirectory()
{
return cAliasDirectory;
}
/**
* A value of 'false' causes a preprocessing only in the current directory,
* a value of 'true' causes a recursive traversing starting in the current directory.<br>
* <b>The default is 'true' (traversing recursively</b>
*/
protected void setRecursiveMode(boolean aRecursive)
{
mTraverseRecursively = aRecursive;
}
// ************ public methods ******************************************************
public void workFile(File aFile)
{
workFile(aFile, true);
}
/**
* Builds the url to the properties file with all mandantory http - parameters.
* Executes the file through the HtmlLoader. Stores the result in the users properties directory
* and cuts the jsp ending.
*/
public void workFile (File aFile, boolean aDeleteTemp)
{
String tPath = aFile.getAbsolutePath();
//makes the path unix conform
File tempFile = null;
String tKey = tPath;
try{
long tWorkStart = System.currentTimeMillis();
if (tPath.endsWith(".jsp")) //only for jsp files
{
File tFile = (File) mTempFileHash.get(tKey);
if(tFile != null) {
tPath = tFile.getAbsolutePath();
System.out.println("[reusing copy] "+tPath);
} else {
if (mCommentsOn)
{
tempFile = replaceComments(aFile);
tPath = tempFile.getAbsolutePath();
System.out.println("replace comments in "+tPath);
}
else
{
boolean tooLong = aFile.toString().length() > 50;
if(tooLong && mTomcat) {
tempFile = createTempFile(aFile);
tPath = tempFile.getAbsolutePath();
System.out.println("copied to "+tPath);
}
}
}
String tUrl = computeWorkUrl(tPath);
//append the http parameter to the properties file
tUrl += getParamString();
HtmlLoader2 tLoader = new HtmlLoader2(); //because the htmlloader has a memory lead
//initialize it new for each work file
//process through jsp engine the file
tLoader.load(tUrl, 0);
if (tLoader.getStatusCode() != 200){
mErrors ++;
printConnectionError(tLoader);
}
else
{
//get the content
String tContent = tLoader.getContent();
String[] tErrorStrings = {
"<h1>Error: 500</h1>",
"<h1>500 Servlet Exception</h1>"
};
int tIndex = -1;
for(int i = 0; i < tErrorStrings.length; i++) {
tIndex = tContent.indexOf(tErrorStrings[i]);
if(tIndex != -1) {
break;
}
}
if(tIndex != -1) {
System.out.println("Error occured on the server side. Please see the tomcat console!");
System.out.println(tContent.substring(tIndex));
System.out.println("!!!! The file " + aFile.getAbsolutePath() + " will not be stored !!!!");
mErrors ++;
return;
}
String tFileContent = filterContent(tContent);
//make the file path to the users config directory
String tNewFilePath = computeNewFilePath(aFile);
storeFile (tFileContent, tNewFilePath);
tContent = null;
}
}
}
catch (java.net.MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
finally
{
if(tempFile != null) {
if(aDeleteTemp) {
tempFile.delete();
} else {
mTempFileHash.put(tKey, tempFile);
}
}
}
}
public void deleteTempFiles()
{
Enumeration tEnum = mTempFileHash.keys();
while(tEnum.hasMoreElements())
{
String tKey = (String) tEnum.nextElement();
File tFile = (File) mTempFileHash.get(tKey);
tFile.delete();
}
}
public int getErrors()
{
return mErrors;
}
/**
* Main method. Traverses the directory tree and processes each jsp-file.
*
* @param aStartDir absolute path to the start directory
*/
public void traverse(String aStartDir)
{
DirNavigator tNavigator = new DirNavigator(aStartDir, this);
if (!mTraverseRecursively)
tNavigator.unsetRecursively();
tNavigator.traverse();
System.out.println(mErrors + " errors occurred on the server side!");
}
/**
* If aCommentsOn is true, then the preprocessed files will have all comments included.
* The default is false.
* @param aCommentsOn
*/
public void setCommentsOn(boolean aCommentsOn)
{
mCommentsOn = aCommentsOn;
}
/**
* Initialize the http properties from command line arguments.
* Here http parameter are marked with '-Param'.
*
* @return only the http parameters out of the command line arguments.
*/
public static Properties initHttpProps(
Properties aProps)
{
Enumeration tKeys = aProps.keys();
Properties tProps = new Properties();
while (tKeys.hasMoreElements())
{
String tKey = (String) tKeys.nextElement();
if (tKey.startsWith(cHttpParamMarker))
{
String tValue = aProps.getProperty(tKey);
tKey = tKey.substring(cHttpParamMarker.length(), tKey.length());
tProps.put (tKey, tValue);
}
}
return tProps;
}
// ************ helper methods ******************************************************
/**
* Returns the http parameter string.
*/
protected String getParamString()
{
StringBuffer tSb = new StringBuffer();
String tRetStr = null;
Properties tParams = getHttpParams();
Enumeration tEnum = tParams.keys();
while (tEnum.hasMoreElements())
{
String tKey = (String)tEnum.nextElement();
String tValue = tParams.getProperty(tKey);
tSb.append(tKey + "=" + tValue);
if (tEnum.hasMoreElements())
{
tSb.append("&");
}
}
tRetStr = tSb.toString();
if ((tRetStr != null) && (tRetStr.length() > 0))
{
tRetStr = "?" + tRetStr;
}
return tRetStr;
}
/**
* Replaces all jsp comments in a file with html/js- comments. This is to leave the comments
* in the target file for debugging. Also all spaces will be left.
*
* @param aFile file that has to be converted from jsp comments
* @return a new temp file with replaced comments (stored in o:/KFM = our jsp-temp directory).
*/
protected static File replaceComments(File aFile)
{
String cJspCommentStart = "<%--"; // begin of a jsp comment
String cJspCommentEnd = "--%>"; // end of a jsp comment
String cHtmlCommentStart = "<!-- "; // begin of a html comment to replace
String cHtmlCommentEnd = " -->"; // end of a html comment to replace
String cJsCommentStart = "/* "; // begin of a html comment to replace
String cJsCommentEnd = " */"; // end of a html comment to replace
String cInclude = "<%@ include"; // marks a file to be included
BufferedReader tReader = null; // reads the content of the source file
BufferedWriter tWriter = null; // writes the content of the target file
File tFile = aFile;
String tPath = aFile.getAbsolutePath();
boolean tIsJsFile = false;
if (tPath.toUpperCase().endsWith("JS.JSP"))
tIsJsFile = true;
try
{
tReader = new BufferedReader(new FileReader(aFile));
String tFileName = aFile.getName();
// Creates the new temp file
tFile = new File ("/home/sipdev/KFM/" + tFileName);
tWriter = new BufferedWriter(new FileWriter(tFile));
String tStr = null;
int tScriptIndex = -1;
String tCommentStr = "";
// read the content of the file
while ((tStr = tReader.readLine()) != null)
{
// check the current line if there are comments or includes
int tIndex = 0; // index in the current string to start searching
int tMin = tStr.length(); // next occurrence of comment or include
// = minimum of tStartIndex, tEndIndex and tIncludeIndex
int tStartIndex = 0; // next occurrence of jsp start comment
int tEndIndex = 0; // next occurrence of jsp end comment
int tIncludeIndex = 0; // next occurrence of include
// A html file can contain javascript sequences.
// In such a sequence the comments should be escaped by js-comments.
if (tScriptIndex != -1)
{
// start javascript was found a number of lines before, now find if there is a end javascript.
if (tStr.toUpperCase().indexOf("</SCRIPT>") != -1)
tScriptIndex = -1; // js at end
tIsJsFile = false;
}
else
{
tScriptIndex = tStr.toUpperCase().indexOf("<SCRIPT");
// start javascript found in this line, now find if there is a end javascript tag in this line.
if (tStr.toUpperCase().indexOf("</SCRIPT>") != -1)
{
tScriptIndex = -1; // js at end
tIsJsFile = false;
}
}
// inside a js comment
if (tScriptIndex != -1)
{
tIsJsFile = true;
}
String tTempStr = ""; // holds the content of a comment to write out
boolean tCommentIsWorked = false; // indicator if a comment is written out in this loop
while (tIndex != -1) // while comments or includes are found
{
tMin = tStr.length();
// jsp start comment found
if ((tStartIndex = tStr.indexOf(cJspCommentStart, tIndex)) != -1)
{
// check if to set the minimum
if (tStartIndex < tMin)
tMin = tStartIndex;
}
// jsp end comment found
if ((tEndIndex = tStr.indexOf(cJspCommentEnd, tIndex)) != -1)
{
// check if to set the minimum
if (tEndIndex < tMin)
tMin = tEndIndex;
}
// jsp include found
if ((tIncludeIndex = tStr.indexOf(cInclude, tIndex)) != -1)
{
// check if to set the minimum
if (tIncludeIndex < tMin)
tMin = tIncludeIndex;
}
if (tIncludeIndex == -1 && tEndIndex == -1 && tStartIndex == -1)
{
break; // no more strings found to replace, so handle next line
}
if (tMin == tStartIndex)
{
tCommentStr += tStr; // Append only the start line
tCommentIsWorked = false;
}
else if (tMin == tEndIndex)
{
// End of comment reached.
// tCommentStr contains the piece of code surrounded by comments.
// First check if there are jsp tags inside.
// In this case don't replace the comments because then the
// tags will be processed.
//
// Otherwise replace the start and end comments by html or js comments.
if (tStr.indexOf(cJspCommentStart) == -1)
tCommentStr += tStr; // Append string only because the start index is not appended.
// Else it will be appended twice.
tCommentIsWorked = true;
if (tCommentStr.indexOf("<sip:") != -1)
{
tWriter.write(tCommentStr); // write the comment as it is because it includes Jsp-Tags
tWriter.newLine();
tCommentStr = ""; // Initialize for next iteration
}
else
{
{
tStartIndex = tCommentStr.indexOf(cJspCommentStart);
// handle start comments
String tEnd = "";
// extract end of line
if (tStartIndex + cJspCommentStart.length() < tCommentStr.length())
tEnd = tCommentStr.substring(tStartIndex + cJspCommentStart.length(), tCommentStr.length());
tTempStr = tCommentStr.substring(0, tStartIndex);
if (tIsJsFile)
tTempStr += cJsCommentStart;
else tTempStr += cHtmlCommentStart;
// append end of line
tTempStr += tEnd;
}
{
tEndIndex = tCommentStr.indexOf(cJspCommentEnd);
// handle end comments
String tEnd = "";
// extract end of line
if (tEndIndex + cJspCommentEnd.length() < tTempStr.length())
tEnd = tTempStr.substring(tEndIndex + cJspCommentEnd.length() + 1, tTempStr.length());
tTempStr = tTempStr.substring(0, tEndIndex);
if (tIsJsFile)
tTempStr += cJsCommentEnd;
else tTempStr += cHtmlCommentEnd;
// append end of line
tTempStr += tEnd;
}
}
tWriter.write(tTempStr);
tWriter.newLine();
tCommentStr = "";
}
else if (tMin == tIncludeIndex)
{
// handle includes
// before each include a comment marking the start of the include will be inserted
// and after each include a comment marking the end of the include
//
// Because there is no other code in a include line, we break out of the while loop to
// handle the next line.
String tSrc = tStr;
String tmpStr = tStr.substring(tIncludeIndex + cInclude.length(), tStr.length());
tmpStr = tmpStr.substring(0, tmpStr.indexOf("%>"));
if (tIsJsFile)
tStr = cJsCommentStart;
else tStr = cHtmlCommentStart;
tStr += " Start include "
+ tmpStr;
if (tIsJsFile)
tStr += cJsCommentEnd;
else tStr += cHtmlCommentEnd;
tStr += "\n"
+ tSrc
+ "\n";
if (tIsJsFile)
tStr += cJsCommentStart;
else tStr += cHtmlCommentStart;
tStr += " End include "
+ tmpStr;
if (tIsJsFile)
tStr += cJsCommentEnd;
else tStr += cHtmlCommentEnd;
break;
}
// comment found, increase index
if (tMin != tStr.length())
tIndex = tMin + 1;
else tIndex = -1;
}
if (tCommentIsWorked) // Comment is ready. Reeinititialize tCommentStr.
{
tCommentStr = "";
tCommentIsWorked = false; // next iteration
}
else if (tCommentStr.length() == 0) // Not inside a comment, write out
{
tWriter.write(tStr); // write content
tWriter.newLine();
}
else if (tCommentStr.length() > 0 && tStr.toUpperCase().indexOf(cJspCommentStart) == -1)
{
// The string doesn't contain a start tag so append the string
// because it is inside a comment.
tCommentStr += tStr + "\n";
}
}
tReader.close();
tWriter.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try{
if (tReader != null)
tReader.close();
if (tWriter != null)
tWriter.close();
}
catch (IOException e)
{
// ignore
}
}
return tFile;
}
/**
* Stores the new file content in a new file.
*
* @param aContent the new file's content
* @param aNewFilePath the absolute path of the new file
*/
private void storeFile(
String aContent,
String aNewFilePath)
throws IOException
{
int tIndex;
aNewFilePath = aNewFilePath.replace('\\', '/');
if ((tIndex = aNewFilePath.indexOf(".jsp")) != -1)
aNewFilePath = aNewFilePath.substring(0, tIndex);
//first create directory
File tDir = new File(aNewFilePath.substring(0, aNewFilePath.lastIndexOf("/")));
if (!tDir.exists())
tDir.mkdirs();
File tNewFile = new File (aNewFilePath);
if (tNewFile.exists())
tNewFile.delete();
StringTokenizer tTokenizer = new StringTokenizer(aContent, "\n");
BufferedWriter tWriter = null;
try{
tWriter = new BufferedWriter (new FileWriter(tNewFile));
while (tTokenizer.hasMoreTokens())
{
String tNext = tTokenizer.nextToken();
// if comments on write all newlines and spaces out, else eliminate them
if (!mCommentsOn)
{
tNext = tNext.trim();
}
tWriter.write(tNext);
tWriter.newLine();
}
}
finally
{
if (tWriter != null)
{
try{
tWriter.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
/**
* Builds the url for the tomcat alias to the current file without
* http parameters
*
* @param aAbsolutePath the absolute path to the current file.
*/
private String computeWorkUrl(String aAbsolutePath)
{
//build the jsp alias for the tomcat engine
aAbsolutePath = aAbsolutePath.replace('\\', '/');
int index = aAbsolutePath.indexOf(cAliasDirectory);
if (index != -1)
{
aAbsolutePath = aAbsolutePath.substring(index + cAliasDirectory.length(), aAbsolutePath.length());
aAbsolutePath = cAlias + aAbsolutePath;
}
else {
//default
String tFileName = aAbsolutePath.substring(aAbsolutePath.lastIndexOf("/"), aAbsolutePath.length());
aAbsolutePath = "temp" + tFileName;
}
/* @@@ JD: No checking for Tomcat Aliases or not. Temp Alias is Default. Anything else is not
considered currently. I don't see a quick way to implement a checking. Posponed.
else
{
throw new IllegalArgumentException ("Your path " + aAbsolutePath
+ " don't match to the alias directory " + cAliasDirectory + " for tomcat !");
}
*/
String tUrl = mUrl + cSeparator + aAbsolutePath;
return tUrl;
}
/**
* Prints an error message to standard out if the processing caused an error.
*/
private void printConnectionError(HtmlLoader2 aLoader)
{
//indicates an error on server side. The file will not be saved and the user will be informed!
System.out.println("ERROR occured on server side. The file will not be stored:");
System.out.println(aLoader.getContent());
}
/**
* Creates a temporary file if the filename is bigger than 26 characters.
* In this case tomcat would throw an error.
* The same behaviour occures if the path name is too big. Therefore the temporary file
* will be stored in the /KFM/ directory.
*
* @return File null if no tempfile was necessary
*/
private File createTempFile(File aFile)
throws IOException
{
File tTempFile = new File(cTempDir, System.currentTimeMillis() + ".jsp");
FileUtils.copy(aFile, tTempFile);
return tTempFile;
}
/**
* @param boolean aTomcat true, if you are using tomcat, false otherwise
*/
public static void setTomcat(boolean aTomcat)
{
mTomcat = aTomcat;
}
}