--- /dev/null
+/*
+ * $RCSfile: JSParser.java,v $
+ *
+ * Copyright 2002
+ * CH-1700 Fribourg, Switzerland
+ * All rights reserved.
+ *
+ *========================================================================
+ * Modifications history
+ *========================================================================
+ * $Log: not supported by cvs2svn $
+ * Revision 1.1 2004/02/26 02:25:42 agfitzp
+ * renamed packages to match xml & css
+ *
+ * Revision 1.1 2004/02/05 03:10:08 agfitzp
+ * Initial Submission
+ *
+ * Revision 1.1.2.1 2003/12/12 21:37:24 agfitzp
+ * Experimental work for Classes view
+ *
+ * Revision 1.6 2003/12/10 20:19:16 agfitzp
+ * 3.0 port
+ *
+ * Revision 1.5 2003/06/21 03:48:51 agfitzp
+ * fixed global variables as functions bug
+ * fixed length calculation of instance variables
+ * Automatic outlining is now a preference
+ *
+ * Revision 1.4 2003/05/30 20:53:09 agfitzp
+ * 0.0.2 : Outlining is now done as the user types. Some other bug fixes.
+ *
+ * Revision 1.3 2003/05/28 20:47:58 agfitzp
+ * Outline the document, not the file.
+ *
+ * Revision 1.2 2003/05/28 15:20:00 agfitzp
+ * Trivial change to test CVS commit
+ *
+ * Revision 1.1 2003/05/28 15:17:12 agfitzp
+ * net.sourceforge.phpeclipse.js.core 0.0.1 code base
+ *
+ *========================================================================
+*/
+
+package net.sourceforge.phpeclipse.js.core.parser;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.sourceforge.phpeclipse.js.core.model.*;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.rules.IToken;
+
+/**
+ * DOCUMENT ME!
+ *
+ * @author Addi
+ */
+public class JSParser
+{
+
+ public static final String FUNCTION = "function";
+
+ /**
+ * line separator
+ */
+ public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ /**
+ * Array of system types to ignore.
+ */
+ private static String[] systemClassNames= {"Array","String"};
+
+
+ protected HashMap systemClassMap = new HashMap();
+
+ protected IFile sourceFile;
+ protected IDocument sourceDocument;
+ protected HashMap functions = new HashMap();
+ protected HashMap classes = new HashMap();
+ protected HashMap globalVariables = new HashMap();
+ protected List elementList = new LinkedList();
+ protected JSSyntaxScanner scanner = new JSSyntaxScanner();
+
+ /**
+ * Constructor for JSParser.
+ */
+ public JSParser()
+ {
+ super();
+
+ int i;
+
+ for(i = 0;i < systemClassNames.length; i++)
+ {
+ String aName = systemClassNames[i];
+ systemClassMap.put(aName, aName);
+ }
+ }
+
+ /**
+ * Returns a string containing the contents of the given file. Returns an empty string if there
+ * were any errors reading the file.
+ * @param file
+ *
+ * @return
+ */
+ protected static String getText(IFile file)
+ {
+ try
+ {
+ InputStream in = file.getContents();
+ return streamToString(in);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ protected static String streamToString(InputStream in) throws IOException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buf = new byte[1024];
+ int read = in.read(buf);
+
+ while (read > 0)
+ {
+ out.write(buf, 0, read);
+ read = in.read(buf);
+ }
+
+ return out.toString();
+ }
+
+ /**
+ * Skips ahead and finds next non-whitespace token.
+ *
+ */
+ public IToken nextNonWhitespaceToken()
+ {
+ IToken aToken = scanner.nextToken();
+
+ while (!aToken.isEOF() && aToken.isWhitespace())
+ {
+ aToken = scanner.nextToken();
+ }
+
+ return aToken;
+ }
+
+ /**
+ * Parses the input given by the argument.
+ *
+ * @param file the element containing the input text
+ *
+ * @return an element collection representing the parsed input
+ */
+ public List parse(IFile file)
+ {
+ this.sourceFile = file;
+ return parse(new Document(getText(file)));
+ }
+
+ /**
+ * Parses the input given by the argument.
+ *
+ * @param aSourceDocument the element containing the input text
+ *
+ * @return an element collection representing the parsed input
+ */
+ public List parse(IDocument aSourceDocument)
+ {
+ sourceDocument = aSourceDocument;
+
+ scanner.setRange(sourceDocument, 0, sourceDocument.getLength());
+ IToken token = scanner.nextToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ if (token.equals(JSSyntaxScanner.TOKEN_FUNCTION))
+ {
+ addFunction(expression, offset, length);
+ }
+
+ if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
+ {
+ //We need to check if the token is already a function or class
+ if (functions.containsKey(expression) || classes.containsKey(expression))
+ {
+ token = nextNonWhitespaceToken();
+ if (token.equals(JSSyntaxScanner.TOKEN_MEMBER))
+ {
+ detectInstanceMethod(offset, expression);
+ } else
+ {
+ detectClassMethod(token, offset, expression);
+ }
+ } else
+ {
+ if (expression.equals("var"))
+ {
+ detectGlobalVariable();
+ }
+ }
+ }
+ token = scanner.nextToken();
+ }
+ return elementList;
+ }
+
+ private void addFunction(String expression, int offset, int length)
+ {
+ String functionSignature = getNaked(expression);
+ int braceOffset = functionSignature.indexOf("(");
+ String functionName = functionSignature.substring(0, braceOffset).trim();
+ String arguments =
+ functionSignature.substring(functionSignature.indexOf("("), functionSignature.indexOf(")") + 1);
+
+ if (functionName.indexOf(".") >= 0)
+ {
+ //If the function signature includes .prototype. then it's a member.
+ if (functionName.indexOf(".prototype.") >= 0)
+ {
+ String className = functionName.substring(0, functionName.indexOf("."));
+ String memberName = functionName.substring(functionName.lastIndexOf(".") + 1);
+ JSInstanceMethodElement aMethod =
+ this.addInstanceMethod(memberName, className, arguments, offset, offset, length);
+ detectInstanceMethodContext(className, aMethod);
+ } else
+ {
+ String className = functionName.substring(0, functionName.indexOf("."));
+ if (functions.containsKey(className) || classes.containsKey(className))
+ {
+ String memberName = functionName.substring(functionName.lastIndexOf(".") + 1);
+ JSFunctionElement aMethod =
+ this.addClassMethod(memberName, className, arguments, offset, offset, length);
+ }
+ }
+ } else
+ {
+ if(! functions.containsKey(functionName))
+ {
+ JSFunctionElement aFunction = new JSFunctionElement(this.sourceFile, functionName, arguments, offset, length);
+
+ elementList.add(aFunction);
+ functions.put(functionName, aFunction);
+
+ detectFunctionContext(aFunction);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private void checkForSpecialGlobalTypes(JSGlobalVariableElement aVariable)
+ {
+ IToken token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ if(!checkForDynamicClass(aVariable, token))
+ {
+ checkForAnonymousFunction(aVariable, token);
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ private boolean checkForDynamicClass(JSGlobalVariableElement aVariable, IToken rhsToken)
+ {
+ if (rhsToken.equals(JSSyntaxScanner.TOKEN_DEFAULT))
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+
+ String expression = getExpression(offset, length);
+
+ if (expression.equals("new"))
+ {
+ IToken token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ expression = getExpression(offset, length);
+
+ if(! isSystemClass(expression))
+ {
+ JSClassElement aClass = findOrCreateClass(aVariable.getName());
+ if(aClass != null)
+ {
+ //Tell the class it's dynamically declared: what we will parse as class methods & vars are really instance methods & vars
+ aClass.setPrototype(true);
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ *
+ */
+ private boolean checkForAnonymousFunction(JSGlobalVariableElement aVariable, IToken rhsToken)
+ {
+ if (rhsToken.equals(JSSyntaxScanner.TOKEN_FUNCTION))
+ {
+ String functionName = aVariable.getName();
+ int offset = aVariable.getOffset();
+ int length = aVariable.getLength();
+
+ int functionOffset = scanner.getTokenOffset();
+ int functionLength = scanner.getTokenLength();
+ String functionSignature =
+ getExpression(functionOffset, functionLength);
+ String arguments = getArgumentString(functionSignature);
+
+ JSFunctionElement aFunction = new JSFunctionElement(this.sourceFile, functionName, arguments, offset, functionOffset - offset + functionLength);
+
+ elementList.add(aFunction);
+ functions.put(functionName, aFunction);
+
+ elementList.remove(aVariable);
+ globalVariables.remove(functionName);
+
+ detectFunctionContext(aFunction);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ *
+ */
+ private String getExpression(int offset, int length)
+ {
+ String expression;
+ try {
+ expression = sourceDocument.get(offset, length);//sourceBuffer.substring(offset, offset + length);
+ } catch(BadLocationException e)
+ {
+ expression = "";
+ }
+ return expression;
+ }
+
+ /**
+ *
+ */
+ private void detectGlobalVariable()
+ {
+ IToken token;
+ int length;
+ int offset;
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
+ {
+ int varOffset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ String variableName = getExpression(varOffset, length);
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+ if (expression.equals("="))
+ {
+ JSGlobalVariableElement aVariable = addGlobalVariable(variableName, varOffset);
+ checkForSpecialGlobalTypes(aVariable);
+ }
+ }
+ }
+ }
+ }
+
+ private void detectClassMethod(IToken token, int classOffset, String className)
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ if (expression.equals("."))
+ {
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ String memberName = getExpression(offset, length);
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ expression = getExpression(offset, length);
+ if (expression.equals("="))
+ {
+
+ token = nextNonWhitespaceToken();
+ int tokenOffset = scanner.getTokenOffset();
+ int tokenLength = scanner.getTokenLength();
+
+ if (token.equals(JSSyntaxScanner.TOKEN_FUNCTION))
+ {
+ String functionSignature = getExpression(tokenOffset, tokenLength);
+ String arguments = getArgumentString(functionSignature);
+
+ JSFunctionElement aMethod =
+ addClassMethod(memberName, className, arguments, classOffset, tokenOffset, tokenLength);
+
+
+ } else
+ {
+ addClassVariable(memberName, className, classOffset);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private String getArgumentString(String functionSignature)
+ {
+ return functionSignature.substring(
+ functionSignature.indexOf("("),
+ functionSignature.indexOf(")") + 1);
+ }
+
+ private void detectInstanceMethod(int classOffset, String className)
+ {
+ String expression;
+ IToken token;
+ int length;
+ int offset;
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ expression = getExpression(offset, length);
+
+ if (expression.equals("."))
+ {
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ String memberName = getExpression(offset, length);
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ expression = getExpression(offset, length);
+ if (expression.equals("="))
+ {
+ token = nextNonWhitespaceToken();
+ if (token.equals(JSSyntaxScanner.TOKEN_FUNCTION))
+ {
+ int functionOffset = scanner.getTokenOffset();
+ int functionLength = scanner.getTokenLength();
+ String functionSignature =
+ getExpression(functionOffset, functionLength);
+ String arguments = getArgumentString(functionSignature);
+
+ JSInstanceMethodElement aMethod =
+ addInstanceMethod(
+ memberName,
+ className,
+ arguments,
+ classOffset,
+ functionOffset,
+ functionLength);
+
+ detectInstanceMethodContext(className, aMethod);
+
+ } else
+ {
+ addInstanceVariable(memberName, className, classOffset, (".prototype.").length());
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void parseInstanceMethodContext(String className, JSFunctionElement aMethod)
+ {
+ IToken token;
+
+ token = nextNonWhitespaceToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ // if (token.equals(JSSyntaxScanner.TOKEN_END_CONTEXT))
+ if (expression.equals("}"))
+ {
+ return;
+ } else if (expression.equals("{"))
+ {
+ parseInstanceMethodContext(className, aMethod);
+ } else if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
+ {
+ if (expression.equals("this"))
+ {
+ handleThisReference(className, offset);
+ }
+ }
+
+ token = nextNonWhitespaceToken();
+ }
+ }
+
+ private void detectInstanceMethodContext(String className, JSFunctionElement aMethod)
+ {
+ IToken token;
+
+ token = nextNonWhitespaceToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ // if (token.equals(JSSyntaxScanner.TOKEN_BEGIN_CONTEXT))
+ if (expression.equals("{"))
+ {
+ parseInstanceMethodContext(className, aMethod);
+ return;
+ }
+
+ token = nextNonWhitespaceToken();
+ }
+ }
+
+ private void parseClassMethodContext(JSFunctionElement aMethod)
+ {
+ IToken token;
+
+ token = nextNonWhitespaceToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ if (expression.equals("}"))
+ {
+ return;
+ } else if (expression.equals("{"))
+ {
+ parseClassMethodContext(aMethod);
+ }
+
+ token = nextNonWhitespaceToken();
+ }
+ }
+
+ private void detectClassMethodContext(JSFunctionElement aMethod)
+ {
+ IToken token = nextNonWhitespaceToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ if (expression.equals("{"))
+ {
+ parseClassMethodContext(aMethod);
+ return;
+ }
+
+ token = nextNonWhitespaceToken();
+ }
+ }
+
+ private void handleThisReference(String className, int expressionStart)
+ {
+ IToken token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+
+ String expression = getExpression(offset, length);
+
+ if(expression.equals("."))
+ {
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ int memberStart = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+
+ String memberName = getExpression(memberStart, length);
+
+ token = nextNonWhitespaceToken();
+ if (!token.isEOF())
+ {
+ offset = scanner.getTokenOffset();
+ length = scanner.getTokenLength();
+ expression = getExpression(offset, length);
+
+ if (expression.equals("="))
+ {
+ addInstanceVariable(memberName, className, expressionStart, 1 + 4 - className.length());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void parseFunctionContext(JSFunctionElement aFunction)
+ {
+ IToken token;
+
+ token = nextNonWhitespaceToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ if (expression.equals("}"))
+ {
+ return;
+ } else if (expression.equals("{"))
+ {
+ parseFunctionContext(aFunction);
+ } else if (token.equals(JSSyntaxScanner.TOKEN_DEFAULT))
+ {
+ if (expression.equals("this"))
+ {
+ handleThisReference(aFunction.getName(), offset);
+ }
+ }
+
+ token = nextNonWhitespaceToken();
+ }
+ }
+
+ private void detectFunctionContext(JSFunctionElement aFunction)
+ {
+ IToken token = nextNonWhitespaceToken();
+ while (!token.isEOF())
+ {
+ int offset = scanner.getTokenOffset();
+ int length = scanner.getTokenLength();
+ String expression = getExpression(offset, length);
+
+ if (expression.equals("{"))
+ {
+ parseFunctionContext(aFunction);
+ return;
+ }
+
+ token = nextNonWhitespaceToken();
+ }
+ }
+
+ private JSInstanceMethodElement addInstanceMethod(
+ String memberName,
+ String className,
+ String arguments,
+ int classOffset,
+ int functionOffset,
+ int functionLength)
+ {
+ int signatureLength = functionOffset - classOffset + functionLength;
+ JSInstanceMethodElement aMethod =
+ new JSInstanceMethodElement(this.sourceFile, memberName, arguments, classOffset, signatureLength);
+
+ findOrCreateClass(className).addChildElement(aMethod);
+
+ return aMethod;
+ }
+
+ private JSFunctionElement addClassMethod(
+ String memberName,
+ String className,
+ String arguments,
+ int classOffset,
+ int functionOffset,
+ int functionLength)
+ {
+ JSClassElement aClass = findOrCreateClass(className);
+ int signatureLength = functionOffset - classOffset + functionLength;
+ JSFunctionElement aMethod;
+
+ if(aClass.isPrototype()) {
+ aMethod = new JSInstanceMethodElement(this.sourceFile, memberName, arguments, classOffset, signatureLength);
+
+ aClass.addChildElement(aMethod);
+ detectInstanceMethodContext(className, aMethod);
+ } else {
+ aMethod = new JSClassMethodElement(this.sourceFile, memberName, arguments, classOffset, signatureLength);
+
+ aClass.addChildElement(aMethod);
+ detectClassMethodContext(aMethod);
+ }
+
+ return aMethod;
+ }
+
+ /**
+ * @param memberName
+ * @param className
+ * @param classOffset
+ * @return
+ */
+ private JSElement addClassVariable(String memberName, String className, int classOffset)
+ {
+ //One extra char for "."
+ JSElement aVariable;
+ JSClassElement aClass = findOrCreateClass(className);
+
+ if(aClass.isPrototype())
+ {
+ aVariable = new JSInstanceVariableElement(this.sourceFile, memberName, classOffset, className.length() + memberName.length() + 1);
+
+ } else {
+ aVariable = new JSClassVariableElement(this.sourceFile, memberName, classOffset, className.length() + memberName.length() + 1);
+ }
+ aClass.addChildElement(aVariable);
+
+ return aVariable;
+ }
+
+ private JSInstanceVariableElement addInstanceVariable(
+ String memberName,
+ String className,
+ int classOffset,
+ int paddingWidth)
+ {
+ //11 extra chars for ".prototype."
+ JSInstanceVariableElement aVariable =
+ new JSInstanceVariableElement(
+ this.sourceFile,
+ memberName,
+ classOffset,
+ className.length() + memberName.length() + paddingWidth);
+
+ findOrCreateClass(className).addChildElement(aVariable);
+
+ return aVariable;
+ }
+
+ private JSGlobalVariableElement addGlobalVariable(String variableName, int offset)
+ {
+ JSGlobalVariableElement aVariable;
+ if (!globalVariables.containsKey(variableName))
+ {
+ aVariable = new JSGlobalVariableElement(this.sourceFile, variableName, offset, variableName.length());
+
+ elementList.add(aVariable);
+ globalVariables.put(variableName, aVariable);
+ } else
+ {
+ aVariable = (JSGlobalVariableElement) classes.get(variableName);
+ }
+
+ return aVariable;
+ }
+
+ private JSClassElement findOrCreateClass(String className)
+ {
+ JSClassElement aClass = null;
+ if (!classes.containsKey(className))
+ {
+ if(functions.containsKey(className))
+ {
+ //if we're creating a class from an existing function we must
+ //migrate the existing function to become a constructor in the class.
+ JSFunctionElement constructor = (JSFunctionElement) functions.get(className);
+
+ aClass = new JSClassElement(this.sourceFile, className, constructor.getStart(), constructor.getLength());
+ aClass.addChildElement(constructor);
+
+ elementList.remove(constructor);
+ elementList.add(aClass);
+ classes.put(className, aClass);
+ } else if(globalVariables.containsKey(className))
+ {
+ //if we're creating a class from an existing global variable we must
+ //migrate the existing function to become a constructor in the class.
+ JSGlobalVariableElement aVariable = (JSGlobalVariableElement) globalVariables.get(className);
+
+ aClass = new JSClassElement(this.sourceFile, className, aVariable.getStart(), aVariable.getLength());
+
+ elementList.remove(aVariable);
+ elementList.add(aClass);
+ classes.put(className, aClass);
+ globalVariables.remove(className);
+ } else {
+ //The final case is if we have no idea where this class came from, but shouldn't be ignored.
+ aClass = new JSClassElement(this.sourceFile, className, 0, 0);
+
+ elementList.add(aClass);
+ classes.put(className, aClass);
+ }
+ } else
+ {
+ aClass = (JSClassElement) classes.get(className);
+ }
+
+ return aClass;
+ }
+
+ public boolean isSystemClass(String aClassName)
+ {
+ return systemClassMap.containsKey(aClassName);
+ }
+
+ /**
+ * Method getNaked.
+ * @param funcName
+ */
+ private String getNaked(String funcName)
+ {
+ if (funcName == null)
+ {
+ return null;
+ }
+
+ funcName = funcName.trim().substring(FUNCTION.length()).trim();
+ funcName = replaceInString(funcName.trim(), LINE_SEPARATOR, "");
+
+ StringBuffer strBuf = new StringBuffer("");
+ int len = funcName.length();
+ boolean wasSpace = false;
+ for (int i = 0; i < len; i++)
+ {
+ char ch = funcName.charAt(i);
+ if (ch == ' ')
+ {
+ wasSpace = true;
+ } else // not space
+ {
+ if (wasSpace)
+ {
+ strBuf.append(' ');
+ }
+ strBuf.append(ch);
+ wasSpace = false;
+ }
+ }
+ return strBuf.toString();
+ }
+
+ /**
+ * replace in a string a string sequence with another string sequence
+ */
+ public static String replaceInString(String source, String whatBefore, String whatAfter)
+ {
+ if (null == source || source.length() == 0)
+ {
+ return source;
+ }
+ int beforeLen = whatBefore.length();
+ if (beforeLen == 0)
+ {
+ return source;
+ }
+ StringBuffer result = new StringBuffer("");
+ int lastIndex = 0;
+ int index = source.indexOf(whatBefore, lastIndex);
+ while (index >= 0)
+ {
+ result.append(source.substring(lastIndex, index));
+ result.append(whatAfter);
+ lastIndex = index + beforeLen;
+
+ // get next
+ index = source.indexOf(whatBefore, lastIndex);
+ }
+ result.append(source.substring(lastIndex));
+ return result.toString();
+ }
+
+ /**
+ * @return Returns the elementList.
+ */
+ public List getElementList() {
+ return elementList;
+ }
+
+}
\ No newline at end of file