added org.eclipse.epf.web.search project. This is the web search core component for epf
diff --git a/org.eclipse.epf.web.search/.classpath b/org.eclipse.epf.web.search/.classpath
new file mode 100644
index 0000000..0a604b9
--- /dev/null
+++ b/org.eclipse.epf.web.search/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="lib" path="lib/icu4j_3_4.jar"/>
+ <classpathentry kind="lib" path="lib/lucene-core-1.9.1.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.epf.web.search/.packaging b/org.eclipse.epf.web.search/.packaging
new file mode 100644
index 0000000..a336b0b
--- /dev/null
+++ b/org.eclipse.epf.web.search/.packaging
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configurations/>
diff --git a/org.eclipse.epf.web.search/.project b/org.eclipse.epf.web.search/.project
new file mode 100644
index 0000000..b642b1f
--- /dev/null
+++ b/org.eclipse.epf.web.search/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.epf.web.search</name>
+ <comment></comment>
+ <projects>
+ <project>Lucene 1.9.1</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.epf.web.search/epf-web-search.jardesc b/org.eclipse.epf.web.search/epf-web-search.jardesc
new file mode 100644
index 0000000..30ed911
--- /dev/null
+++ b/org.eclipse.epf.web.search/epf-web-search.jardesc
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="WINDOWS-1252"?>
+<jardesc>
+<jar path="D:/EPF Workspaces/epf-head/org.eclipse.epf.publishing/docroot/WEB-INF/lib/epf-web-search.jar"/>
+<options buildIfNeeded="true" compress="true" descriptionLocation="/org.eclipse.epf.web.search/epf-web-search.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+<selectedProjects/>
+<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+<sealing sealJar="false">
+<packagesToSeal/>
+<packagesToUnSeal/>
+</sealing>
+</manifest>
+<selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
+<javaElement handleIdentifier="=org.eclipse.epf.web.search/src"/>
+</selectedElements>
+</jardesc>
diff --git a/org.eclipse.epf.web.search/lib/icu4j_3_4.jar b/org.eclipse.epf.web.search/lib/icu4j_3_4.jar
new file mode 100644
index 0000000..d35e3c3
--- /dev/null
+++ b/org.eclipse.epf.web.search/lib/icu4j_3_4.jar
Binary files differ
diff --git a/org.eclipse.epf.web.search/lib/lucene-core-1.9.1.jar b/org.eclipse.epf.web.search/lib/lucene-core-1.9.1.jar
new file mode 100644
index 0000000..f143e9d
--- /dev/null
+++ b/org.eclipse.epf.web.search/lib/lucene-core-1.9.1.jar
Binary files differ
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/DefaultSearchService.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/DefaultSearchService.java
new file mode 100644
index 0000000..dc6d4a5
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/DefaultSearchService.java
@@ -0,0 +1,5 @@
+package org.eclipse.epf.web.search;
+
+public class DefaultSearchService {
+
+}
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/IndexLoader.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/IndexLoader.java
new file mode 100644
index 0000000..78ed928
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/IndexLoader.java
@@ -0,0 +1,309 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2007 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.eclipse.epf.web.search.utils.UNCUtil;
+
+
+public class IndexLoader {
+ public static final String VERSION_FILE_NAME = "version.txt";
+ public static final String VERSION_DELIMITER = "*";
+ public static final String DOWNLOAD_ERROR = "Unable to download index.jar file";
+
+ private static String userIndexFolderName = null;
+ private String userIndexPath = null;
+ private static Map cache = new HashMap();
+
+ protected String m_docBase;
+ protected String m_indexFolder;
+ protected String m_indexFile;
+ protected long tally;
+ protected int fileSize;
+
+ public String downloadIndex() {
+ byte bytes[] = new byte[16384];
+
+ String product = "";
+ File versionFile = null;
+ File indexArchive = null;
+
+ try {
+ // TBD replace 100 with something to do with archive size or
+ // something
+ StringBuffer base = new StringBuffer(m_docBase);
+ base.append("/search/index/index.jar");
+
+ URL url = new URL(base.toString());
+ // handle UNC
+ url = UNCUtil.handleURLForUNC(url);
+
+ // File folder = new File(m_indexFolder);
+ // folder = folder.getParentFile();
+ //
+ // if (folder.exists())
+ // {
+ // folder.delete();
+ // }
+
+ indexArchive = new File(m_indexFile);
+ indexArchive.getParentFile().mkdirs();
+
+ StringBuffer newIndexFolderName = new StringBuffer(m_indexFolder);
+ newIndexFolderName.append(userIndexFolderName);
+
+ // let's get the attrbutes of the file we want to download.
+ versionFile = new File(newIndexFolderName.toString()
+ + File.separator + VERSION_FILE_NAME);
+ FileReader readVersion = new FileReader(versionFile);
+ BufferedReader bRead = new BufferedReader(readVersion);
+ String versionString = bRead.readLine();
+ bRead.close();
+ readVersion.close();
+ StringTokenizer tok = new StringTokenizer(versionString,
+ VERSION_DELIMITER);
+ product = tok.nextToken();
+ tok.nextToken();
+ fileSize = Integer.parseInt(tok.nextToken());
+
+ BufferedInputStream inputS = new BufferedInputStream(url
+ .openStream());
+ FileOutputStream writeArchive = new FileOutputStream(indexArchive);
+
+ // System.out.println("docBase: " + m_docBase);
+
+ tally = 0;
+ int streamNotAvailable = 0;
+
+ // System.out.println("Downloading index file: " + url.toString());
+ // System.out.println("fileSize: " + fileSize);
+
+ while (tally < fileSize) {
+ int num = inputS.read(bytes);
+
+ // inputS.available() is not implemented for some imput stream,
+ // such as strem from https url. The value will always be 0
+ if (/* inputS.available() */num > 0) {
+ streamNotAvailable = 0;
+ writeArchive.write(bytes, 0, num);
+ tally = tally + num;
+ } else {
+ try {
+ // this will cause invalid thread exeception
+ // since the thread may not own the object's monitor
+ // use synchronized key to force the thread to own the
+ // object's monitor
+ synchronized (this) {
+ wait(50);
+ }
+
+ if (streamNotAvailable > 100) {
+ System.out.println("time out: " + DOWNLOAD_ERROR);
+ throw new Exception(DOWNLOAD_ERROR);
+ }
+ streamNotAvailable++;
+ } catch (Exception e1) {
+ System.out.println("Download index failed");
+ // display.setText(display.getText() + "\nDownload index
+ // failed");
+ e1.printStackTrace();
+ break;
+ }
+ }
+ }
+
+ inputS.close();
+ writeArchive.close();
+ tally = 0;
+
+ ZipInputStream zStream = new ZipInputStream(new FileInputStream(
+ m_indexFile));
+ ZipEntry zEntry = zStream.getNextEntry();
+ while (zEntry != null) {
+ File file = new File(newIndexFolderName.toString(), zEntry
+ .getName());
+
+ if (zEntry.isDirectory()) {
+ file.mkdir();
+ } else {
+ file.getParentFile().mkdirs();
+ FileOutputStream outs = new FileOutputStream(file);
+ while (zStream.available() > 0) {
+ int num = zStream.read(bytes);
+ if (num > 0) {
+ outs.write(bytes, 0, num);
+ }
+ }
+ outs.close();
+ tally++;
+ }
+
+ zEntry = zStream.getNextEntry();
+ }
+ zStream.close();
+
+ System.out
+ .println("Completed writing the index files successfully");
+ } catch (Exception e1) {
+ System.out.println(e1.getMessage());
+ product = null;
+ versionFile.delete();
+
+ e1.printStackTrace();
+ } finally {
+ if (indexArchive.exists())
+ indexArchive.delete();
+
+ }
+
+ return product;
+ }
+
+ /**
+ * Constructor for IndexLoader
+ */
+ public IndexLoader(String documentBase, String indexFolder, String indexFile) {
+ m_docBase = documentBase;
+ m_indexFolder = indexFolder;
+ m_indexFile = indexFile;
+ }
+
+ /**
+ * Determines whether the index version is out of date.
+ */
+ public String checkIndexVersion() throws Exception {
+ String siteFolderName = null;
+
+ try {
+ URL url = new URL(m_docBase
+ + "/search/index/version.txt"); //$NON-NLS-1$
+ // handle UNC
+ url = UNCUtil.handleURLForUNC(url);
+
+ BufferedInputStream inputS = new BufferedInputStream(url
+ .openStream());
+ InputStreamReader iStreamReader = new InputStreamReader(inputS);
+ BufferedReader read = new BufferedReader(iStreamReader);
+ String version = read.readLine();
+ int idx = (version != null) ? version.indexOf(VERSION_DELIMITER)
+ : -1;
+ if (idx > -1) {
+ String localFolderName = version.substring(idx + 1);
+ userIndexFolderName = removeChar(localFolderName, '*');
+ } else {
+ throw new FileNotFoundException();
+ }
+ read.close();
+
+ if (userIndexFolderName == null) {
+ throw new FileNotFoundException();
+ }
+
+ userIndexPath = m_indexFolder + userIndexFolderName;
+
+ String userStringVersion = ""; //$NON-NLS-1$
+ File userVersion = new File(userIndexPath + File.separator
+ + "version.txt"); //$NON-NLS-1$
+ if (userVersion.exists()) {
+ FileReader fRead = new FileReader(userVersion);
+ read = new BufferedReader(fRead);
+ userStringVersion = read.readLine();
+ read.close();
+ }
+ if (version.equals(userStringVersion)) {
+ siteFolderName = userStringVersion.substring(0,
+ userStringVersion.indexOf("*")); //$NON-NLS-1$
+ } else {
+ userVersion.delete();
+ userVersion.getParentFile().delete();
+ userVersion.getParentFile().mkdirs();
+ FileWriter fWrite = new FileWriter(userVersion);
+ BufferedWriter write = new BufferedWriter(fWrite);
+ write.write(version + "\n"); //$NON-NLS-1$
+ write.close();
+ }
+ } catch (FileNotFoundException e) {
+ // try {
+ // IndexBuilder indexBuilder = new IndexBuilder(pathDocumentBase);
+ // indexBuilder.createIndex();
+ // siteFolderName = checkIndexVersion(pathDocumentBase,
+ // indexLocation);
+ // return siteFolderName;
+ // } catch (Exception e2) {
+ // e2.printStackTrace();
+ // }
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+
+ return siteFolderName;
+ }
+
+ public static String getSiteFolderName(String documentBase) throws Exception {
+ String siteFolderName = (String) cache.get(documentBase);
+
+ if (siteFolderName != null)
+ return siteFolderName;
+
+ try {
+ URL url = new URL(documentBase + "/search/index/version.txt"); //$NON-NLS-1$
+ // handle UNC
+ url = UNCUtil.handleURLForUNC(url);
+
+ BufferedInputStream inputS = new BufferedInputStream(url
+ .openStream());
+ InputStreamReader iStreamReader = new InputStreamReader(inputS);
+ BufferedReader read = new BufferedReader(iStreamReader);
+ String version = read.readLine();
+ int idx = (version != null) ? version.indexOf(VERSION_DELIMITER)
+ : -1;
+ if (idx > -1) {
+ siteFolderName = version.substring(0, idx);
+ cache.put(documentBase, siteFolderName);
+ } else {
+ throw new FileNotFoundException();
+ }
+ read.close();
+
+ if (siteFolderName == null) {
+ throw new FileNotFoundException();
+ }
+ } catch (FileNotFoundException fnfe) {
+ fnfe.printStackTrace();
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+
+ return siteFolderName;
+ }
+
+ public static String removeChar(String s, char c) {
+ String r = "";
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) != c)
+ r += s.charAt(i);
+ }
+ return r;
+ }
+
+ public String getUserIndexPath() {
+ return userIndexPath;
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/IndexSearch.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/IndexSearch.java
new file mode 100644
index 0000000..a894a84
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/IndexSearch.java
@@ -0,0 +1,145 @@
+package org.eclipse.epf.web.search;
+
+import java.util.StringTokenizer;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.store.RAMDirectory;
+import org.eclipse.epf.web.search.analysis.ChineseAnalyzer;
+import org.eclipse.epf.web.search.analysis.TextAnalyzer;
+
+import com.ibm.icu.text.DecimalFormat;
+
+public class IndexSearch {
+
+ private static Searcher searcher;
+
+ public static Hits search(String indexLocation, String inputQuery,
+ String searchField) {
+
+ Hits hits = null;
+ Query q = null;
+ String queryString = null;
+ DecimalFormat scoreFormatter = new DecimalFormat("0.######");
+
+ if (indexLocation == null || inputQuery == null || searchField == null
+ || searchField.length() == 0 || inputQuery.length() == 0)
+ return null;
+
+ try {
+ queryString = detectHyphenated(inputQuery);
+
+ if (queryString == null || queryString.length() == 0)
+ return null;
+
+ if (searcher == null) {
+ searcher = new IndexSearcher(new RAMDirectory(indexLocation));
+// searcher = new IndexSearcher(FSDirectory.getDirectory(indexLocation,
+// false));
+ }
+
+ if ( searcher == null ) {
+ return hits;
+ }
+
+// Sort sort = new Sort(new SortField[]{
+// new SortField("title"),
+// new SortField("summary")
+// });
+
+ // per user's request, the sorting should be based on the hit rate,
+ // so don't pass in any sorting criteria
+ Sort sort = null;
+
+ try {
+
+ q = QueryParser.parse(queryString, searchField,
+ new TextAnalyzer());
+ if ( q != null ) {
+ hits = searcher.search(q, (Sort)sort);
+ }
+ } catch (Throwable th ) {
+
+ }
+
+ // note: icu4j failed with jre 1.5 in server mode.
+ // in such a case, try the old one
+ q = QueryParser.parse(queryString, searchField,
+ new ChineseAnalyzer());
+ if ( q != null ) {
+ hits = searcher.search(q, (Sort)sort);
+ }
+
+ return hits;
+
+
+ } catch (ParseException pe) {
+ pe.printStackTrace();
+ } catch (java.io.IOException io) {
+ io.printStackTrace();
+ } catch (Throwable p1) {
+ p1.printStackTrace();
+ }
+
+ return hits;
+ }
+
+ /*
+ * detect hyphenated words and if hyphenate, put quotes around so that they are
+ * considered one word for example,"use-case" as opposed to use-case, which Lucene
+ * interprets as "use" NOT "case" which is not what we want. algorithm: first tokenize
+ * by space to isolate words next, if words have hyphens, put quotes at the beginning
+ * and end append to buffer
+ */
+ public static String detectHyphenated(String queryString) {
+ StringTokenizer spaceTokenizer = new StringTokenizer(queryString);
+ StringBuffer wordBuffer = new StringBuffer();
+
+ while (spaceTokenizer.hasMoreTokens()) {
+ // isolate into words
+ String word = spaceTokenizer.nextToken();
+ if ((word.indexOf('-') != -1 ) && !word.startsWith("\"")) //$NON-NLS-1$
+ {
+ // hyphen found, and word is not already an exact phrase,
+ // so add quotes to beginning and end of word
+ wordBuffer.append("\""); //$NON-NLS-1$
+ wordBuffer.append(word);
+ wordBuffer.append("\""); //$NON-NLS-1$
+ //System.out.println("if: " + wordBuffer.toString());
+ } else {
+ //System.out.println("else: " + queryString);
+ return queryString; //RATLC00251031
+ //wordBuffer.append(word);
+ }
+ if (spaceTokenizer.hasMoreTokens()) {
+ wordBuffer.append(" "); //$NON-NLS-1$
+ }
+ }
+
+
+ return wordBuffer.toString();
+ }
+
+ /**
+ * @param args
+ */
+// public static void main(String[] args) {
+// if (args.length > 0) {
+// // String rupPath = System.getProperty( "user.home" ) + java.io.File.separator
+// // + "rup";
+// String rupPath = args[0];
+// SortedHits sortedHits = IndexSearch.search(rupPath + "\\index", "Analyst",
+// "contents");
+// System.out
+// .println("There are " + sortedHits.length() + " hits for 'analyst'");
+// }
+//
+// }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/SEARCH.properties b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/SEARCH.properties
new file mode 100644
index 0000000..3bf392a
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/SEARCH.properties
@@ -0,0 +1,9 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2003, 2007 IBM Corporation. All Rights Reserved.
+#-------------------------------------------------------------------------------
+# NLS_MESSAGEFORMAT_VAR
+nextActionText=Next
+previousActionText=Previous
+# note: these words should be all lowercase
+SearchFailed=Search request failed
+
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/SearchResources.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/SearchResources.java
new file mode 100644
index 0000000..58f4d3c
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/SearchResources.java
@@ -0,0 +1,23 @@
+package org.eclipse.epf.web.search;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public class SearchResources {
+ private static final String BUNDLE_NAME = "org.eclipse.epf.web.search.SEARCH"; //$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle
+ .getBundle(BUNDLE_NAME);
+
+ private SearchResources() {
+ }
+
+ public static String getString(String key) {
+ // TODO Auto-generated method stub
+ try {
+ return RESOURCE_BUNDLE.getString(key);
+ } catch (MissingResourceException e) {
+ return '[' + key + ']';
+ }
+ }
+}
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseAnalyzer.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseAnalyzer.java
new file mode 100644
index 0000000..735eebd
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseAnalyzer.java
@@ -0,0 +1,29 @@
+package org.eclipse.epf.web.search.analysis;
+
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+
+
+public class ChineseAnalyzer extends Analyzer {
+
+ /**
+ * Default constructor.
+ */
+ public ChineseAnalyzer()
+ {
+ super();
+ }
+
+ /**
+ * Creates a TokenStream which tokenizes all the text in the provided Reader.
+ *
+ * @return A TokenStream build from a ChineseTokenizer filtered with ChineseFilter.
+ */
+ public final TokenStream tokenStream(String fieldName, Reader reader) {
+ TokenStream result = new ChineseTokenizer(reader);
+ result = new ChineseFilter(result);
+ return result;
+ }
+}
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseFilter.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseFilter.java
new file mode 100644
index 0000000..3cf281f
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseFilter.java
@@ -0,0 +1,120 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2004, 200 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.analysis;
+
+import java.util.Hashtable;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.analysis.StopFilter;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.TokenFilter;
+import org.apache.lucene.analysis.TokenStream;
+
+
+public class ChineseFilter extends TokenFilter {
+
+ private Hashtable _stopTable;
+
+ public ChineseFilter(TokenStream in)
+ {
+ super(in);
+
+ input = in;
+
+ if (_stopTable == null) {
+ loadStopWords();
+ }
+ }
+
+ public final Token next() throws java.io.IOException {
+
+ for (Token token = input.next(); token != null; token = input.next()) {
+ String text = token.termText();
+
+ if (_stopTable.get(text) == null) {
+ switch (Character.getType(text.charAt(0))) {
+
+ // June 3, 2003 - fchong added support for digits for Rational
+ case Character.DECIMAL_DIGIT_NUMBER:
+ case Character.LETTER_NUMBER:
+ case Character.LOWERCASE_LETTER:
+ case Character.UPPERCASE_LETTER:
+
+ // English word/token should larger than 1 character.
+ if (text.length()>1) {
+ return token;
+ }
+ break;
+ case Character.OTHER_LETTER:
+
+ // One Chinese character as one Chinese word.
+ // Chinese word extraction to be added later here.
+
+ return token;
+ }
+
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * Loads the stop words defined in the StopWords.properties file.
+ */
+ private void loadStopWords() {
+ String[] words = null;
+ try {
+ ResourceBundle bundle = ResourceBundle.getBundle(ChineseFilter.class
+ .getPackage().getName()
+ + ".StopWords"); //$NON-NLS-1$
+ String property = bundle.getString("Search.stopWords"); //$NON-NLS-1$
+ words = split(property, " ,", -1); //$NON-NLS-1$
+ } catch (Exception e) {
+ words = StopAnalyzer.ENGLISH_STOP_WORDS;
+ }
+ _stopTable = StopFilter.makeStopTable(words);
+ }
+
+ /**
+ * Splits a string into an array of string tokens.
+ *
+ * @param str
+ * A string.
+ * @param sep
+ * A string containing the string separators.
+ * @param count
+ * The desired number of string tokens.
+ * @return An array of string tokens.
+ */
+ public static String[] split(String str, String sep, int count) {
+ if (str == null || count == 0 || count < -1) {
+ return null;
+ }
+
+ StringTokenizer tokenizer = new StringTokenizer(str, sep,
+ count == -1 ? false : true);
+
+ if (count == -1) {
+ count = tokenizer.countTokens();
+ }
+
+ String[] result = new String[count];
+ int i = 0;
+ while (tokenizer.hasMoreTokens()) {
+ String t = tokenizer.nextToken();
+ if (i < count) {
+ if ((t.length() == 1) && (sep.indexOf(t) != -1)) {
+ continue;
+ }
+ result[i++] = t;
+ } else {
+ result[count - 1] += t;
+ }
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseTokenizer.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseTokenizer.java
new file mode 100644
index 0000000..181ebfb
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/ChineseTokenizer.java
@@ -0,0 +1,87 @@
+package org.eclipse.epf.web.search.analysis;
+
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.Tokenizer;
+
+public class ChineseTokenizer extends Tokenizer {
+
+ public ChineseTokenizer(Reader in) {
+ input = in;
+ }
+
+ private int offset = 0, bufferIndex=0, dataLen=0;
+ private final static int MAX_WORD_LEN = 255;
+ private final static int IO_BUFFER_SIZE = 1024;
+ private final char[] buffer = new char[MAX_WORD_LEN];
+ private final char[] ioBuffer = new char[IO_BUFFER_SIZE];
+
+
+ private int length;
+ private int start;
+
+
+ private final void push(char c) {
+
+ if (length == 0) start = offset-1; // start of token
+ buffer[length++] = Character.toLowerCase(c); // buffer it
+
+ }
+
+ private final Token flush() {
+
+ if (length>0) {
+ //System.out.println(new String(buffer, 0, length));
+ return new Token(new String(buffer, 0, length), start, start+length);
+ }
+ else
+ return null;
+ }
+
+ public final Token next() throws java.io.IOException {
+
+ length = 0;
+ start = offset;
+
+
+ while (true) {
+
+ final char c;
+ offset++;
+
+ if (bufferIndex >= dataLen) {
+ dataLen = input.read(ioBuffer);
+ bufferIndex = 0;
+ };
+
+ if (dataLen == -1) return flush();
+ else
+ c = (char) ioBuffer[bufferIndex++];
+
+
+ switch(Character.getType(c)) {
+
+ case Character.DECIMAL_DIGIT_NUMBER:
+ case Character.LOWERCASE_LETTER:
+ case Character.UPPERCASE_LETTER:
+ push(c);
+ if (length == MAX_WORD_LEN) return flush();
+ break;
+
+ case Character.OTHER_LETTER:
+ if (length>0) {
+ bufferIndex--;
+ return flush();
+ }
+ push(c);
+ return flush();
+
+ default:
+ if (length>0) return flush();
+ break;
+ }
+ }
+
+ }
+}
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/StopWords.properties b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/StopWords.properties
new file mode 100644
index 0000000..5ca97c3
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/StopWords.properties
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2003, 2007 IBM Corporation. All Rights Reserved.
+#-------------------------------------------------------------------------------
+# NLS_MESSAGEFORMAT_VAR
+
+# Search Stop Words
+Search.stopWords=\
+a, about, an, and, are, as, at, be, but, by, for, from, how, \
+i, if, in, into, is, it, no, not, of, on, or, s, such, \
+t, that, the, their, then, there, these, they, this, to, \
+was, what, when, where, who, will, with
+
+
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextAnalyzer.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextAnalyzer.java
new file mode 100644
index 0000000..b3db689
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextAnalyzer.java
@@ -0,0 +1,34 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2005 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.analysis;
+
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+
+/**
+* A Text Analyzer that handles Unicode 4.1 characters.
+*
+* @author Kelvin Low
+* @since 1.0
+*/
+public class TextAnalyzer extends Analyzer {
+
+ /**
+ * Creates a new instance.
+ */
+ public TextAnalyzer() {
+ super();
+ }
+
+ /**
+ * @see org.apache.lucene.analysis.Analyzer#tokenStream(String, Reader)
+ */
+ public final TokenStream tokenStream(String fieldName, Reader reader) {
+ TokenStream result = new TextTokenizer(reader);
+ return new TextFilter(result);
+ }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextFilter.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextFilter.java
new file mode 100644
index 0000000..7d67b2d
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextFilter.java
@@ -0,0 +1,68 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2007 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.analysis;
+
+import java.io.IOException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.analysis.StopFilter;
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.TokenFilter;
+import org.apache.lucene.analysis.TokenStream;
+import org.eclipse.epf.web.search.utils.StrUtil;
+
+
+
+/**
+* A Text Filter that handles Unicode 4.1 characters.
+*
+* @author Kelvin Low
+* @since 1.0
+*/
+public final class TextFilter extends TokenFilter {
+
+ private static Set stopWords = null;
+
+ /**
+ * Creates a new instance.
+ */
+ public TextFilter(TokenStream in) {
+ super(in);
+ if (stopWords == null) {
+ loadStopWords();
+ }
+ }
+
+ /**
+ * @see org.apache.lucene.analysis.TokenStream#next()
+ */
+ public final Token next() throws IOException {
+ for (Token token = input.next(); token != null; token = input.next()) {
+ String tokenText = token.termText();
+ if (!stopWords.contains(tokenText)) {
+ return token;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Loads the stop words defined in the StopWords.properties file.
+ */
+ private void loadStopWords() {
+ String[] words = null;
+ try {
+ ResourceBundle bundle = ResourceBundle.getBundle(TextFilter.class
+ .getPackage().getName()
+ + ".StopWords"); //$NON-NLS-1$
+ String property = bundle.getString("Search.stopWords"); //$NON-NLS-1$
+ words = StrUtil.split(property, " ,"); //$NON-NLS-1$
+ } catch (Exception e) {
+ words = StopAnalyzer.ENGLISH_STOP_WORDS;
+ }
+ stopWords = StopFilter.makeStopSet(words);
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextTokenizer.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextTokenizer.java
new file mode 100644
index 0000000..3899f99
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/analysis/TextTokenizer.java
@@ -0,0 +1,76 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2005 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.analysis;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Token;
+import org.apache.lucene.analysis.Tokenizer;
+
+import com.ibm.icu.text.BreakIterator;
+
+/**
+* A Text Tokenizer that segments text into words using ICU4J.
+*
+* @author Kelvin Low
+* @since 1.0
+*/
+public final class TextTokenizer extends Tokenizer {
+
+ private final static int BUFFER_SIZE = 4096;
+
+ private String text;
+
+ private BreakIterator iterator;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param reader
+ * The text source.
+ */
+ public TextTokenizer(Reader reader) {
+ super(reader);
+ StringBuffer textBuffer = new StringBuffer(BUFFER_SIZE);
+ char[] buffer = new char[BUFFER_SIZE];
+ int charsRead;
+ try {
+ while ((charsRead = reader.read(buffer, 0, BUFFER_SIZE)) > 0) {
+ textBuffer.append(buffer, 0, charsRead);
+ }
+ text = textBuffer.toString();
+ iterator = BreakIterator.getWordInstance();
+ iterator.setText(text);
+ } catch (IOException e) {
+ iterator = null;
+ }
+ }
+
+ /**
+ * @see org.apache.lucene.analysis.TokenStream#next()
+ */
+ public final Token next() throws IOException {
+ if (iterator != null) {
+ while (true) {
+ int start = iterator.current();
+ int end = iterator.next();
+ if (end != BreakIterator.DONE) {
+ String tokenText = text.substring(start, end).toLowerCase();
+ if (!tokenText.equals(" ")) { //$NON-NLS-1$
+ if (tokenText.endsWith("'s")) { //$NON-NLS-1$
+ tokenText = tokenText.substring(0, tokenText
+ .length() - 2);
+ }
+ return new Token(tokenText, 0, tokenText.length());
+ }
+ } else {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/FileUtil.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/FileUtil.java
new file mode 100644
index 0000000..04c1bd1
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/FileUtil.java
@@ -0,0 +1,409 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2006 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.utils;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+
+import com.ibm.icu.util.ULocale;
+
+/**
+* Implements a utility class for managing directories and files.
+*
+* @author Kelvin Low
+* @since 6.0
+*/
+public class FileUtil {
+
+ /**
+ * Platform-specific line separator.
+ */
+ public static final String LINE_SEP = System.getProperty("line.separator"); //$NON-NLS-1$
+
+ /**
+ * Private constructor to prevent this class from being instantiated. All
+ * methods in this class should be static.
+ */
+ private FileUtil() {
+ }
+
+ /**
+ * Returns the absolute path for the given file or directory.
+ *
+ * @param file
+ * The given file or directory.
+ * @return The absolute path of the given file or directory.
+ */
+ public static String getAbsolutePath(File file) {
+ return file.getAbsolutePath().replace('\\', '/');
+ }
+
+ /**
+ * Returns the absolute path for the given file or directory.
+ *
+ * @param file
+ * The given file or directory name.
+ * @return The absolute path of the given file or directory.
+ */
+ public static String getAbsolutePath(String file) {
+ return getAbsolutePath(new File(file));
+ }
+
+ /**
+ * Returns the absolute path for the given URL.
+ *
+ * @param url
+ * The given URL.
+ * @return The absolute path of the given URL.
+ */
+ public static String getAbsolutePath(URL url) {
+ String pathName = url.getFile().substring(1);
+ String result = NetUtil.decodeUrl(pathName, null);
+ return result;
+ }
+
+ /**
+ * Returns the parent directory of the given path.
+ *
+ * @param path
+ * The path name.
+ * @return The name of the parent directory.
+ */
+ public static String getParentDirectory(String path) {
+ return (new File(path)).getParent();
+ }
+
+ /**
+ * Returns the file name and extension from the given path.
+ *
+ * @param path
+ * The path name.
+ * @return The file name and the file extension.
+ */
+ public static String getFileName(String path) {
+ return getFileName(path, true);
+ }
+
+ /**
+ * Returns the file name from the given path, with or without the file
+ * extension.
+ *
+ * @param path
+ * The path name.
+ * @param withExtension
+ * If true, include the file extension in the result.
+ * @return The file name with or without the file extension.
+ */
+ public static String getFileName(String path, boolean withExtension) {
+ String normalizedPath = path.replace('\\', '/');
+
+ int prefixLength = 0;
+ if (normalizedPath.startsWith(NetUtil.URI_FILE_PREFIX)) {
+ prefixLength = NetUtil.URI_FILE_PREFIX_SIZE;
+ } else if (normalizedPath.startsWith(NetUtil.URI_HTTP_PREFIX)) {
+ prefixLength = NetUtil.URI_HTTP_PREFIX_SIZE;
+ }
+
+ String fileName;
+ int index = normalizedPath.lastIndexOf("/"); //$NON-NLS-1$
+ if (index < prefixLength) {
+ fileName = normalizedPath.substring(prefixLength);
+ } else {
+ fileName = path.substring(index + 1);
+ }
+
+ if (withExtension) {
+ return fileName;
+ }
+
+ index = fileName.indexOf("."); //$NON-NLS-1$
+ return (index > 0) ? fileName.substring(0, index) : fileName;
+ }
+
+ /**
+ * Appends the platform specific path separator to the end of the given
+ * path.
+ *
+ * @param path
+ * The path name.
+ * @return The path name appended with the platform specific path separator.
+ */
+ public static String appendSeparator(String path) {
+ return appendSeparator(path, File.separator);
+ }
+
+ /**
+ * Appends the given path separator to the end of the given path.
+ *
+ * @param path
+ * The path name.
+ * @param separator
+ * The path separator.
+ * @return The path name appended with the given separator.
+ */
+ public static String appendSeparator(String path, String separator) {
+ return path.endsWith(separator) ? path : path + separator;
+ }
+
+ /**
+ * Removes the ending path separator from the given path.
+ *
+ * @param path
+ * The path name.
+ * @return The path name minus the platform specific path separator.
+ */
+ public static String removeSeparator(String path) {
+ return path.endsWith(File.separator) ? path.substring(0,
+ path.length() - 1) : path;
+ }
+
+ /**
+ * Removes the ending path separator from the given path.
+ *
+ * @param path
+ * The path name.
+ * @return The path name minus the path separator "\\" or "/".
+ */
+ public static String removeAllSeparator(String path) {
+ return path.endsWith("/") || path.endsWith("\\") ? path.substring(0, path.length() - 1) : path; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Removes the ending path separator from the given path.
+ *
+ * @param path
+ * The path name.
+ * @param separator
+ * The path separator.
+ * @return The path name minus the separator.
+ */
+ public static String removeSeparator(String path, String separator) {
+ return path.endsWith(separator) ? path.substring(0, path.length() - 1)
+ : path;
+ }
+
+ /**
+ * Replaces the file name with another in the given path.
+ *
+ * @param path
+ * The path name.
+ * @param oldFileName
+ * The old file name.
+ * @param newFileName
+ * The new file name.
+ * @return The new path name with the new file name.
+ */
+ public static String replaceFileName(String path, String oldFileName,
+ String newFileName) {
+ int index = path.lastIndexOf(oldFileName);
+ return path.substring(0, index) + newFileName;
+ }
+
+ /**
+ * Replaces the file extension with another in the given path.
+ *
+ * @param path
+ * The path name.
+ * @param oldFileExt
+ * The old file extension.
+ * @param newFileExt
+ * The new file extension.
+ * @return The new path with the new file extension.
+ */
+ public static String replaceExtension(String path, String oldExt,
+ String newExt) {
+ int index = path.lastIndexOf(oldExt);
+ return path.substring(0, index) + newExt;
+ }
+
+ /**
+ * Returns the locale-specific path of a base path.
+ *
+ * @param path
+ * The base path name.
+ * @param localeStr
+ * The locale string.
+ * @return The locale-specific path.
+ */
+ public static String getLocalePath(String path, String localeStr) {
+ if (StrUtil.isBlank(localeStr)) {
+ return path;
+ }
+ String fileName = getFileName(path);
+ return replaceFileName(path, fileName, localeStr + "/" + fileName); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the locale-specific path of a base path.
+ *
+ * @param path
+ * The base path name.
+ * @param locale
+ * The locale object.
+ * @return The locale-specific path.
+ */
+ public static String getLocalePath(String path, ULocale locale) {
+ return locale == null ? path : getLocalePath(path, locale.toString());
+ }
+
+ /**
+ * Write the given text to a file.
+ *
+ * @param fileName
+ * The target file name.
+ * @param text
+ * The text to write.
+ * @return true if the given text is written successfully to file.
+ */
+ public static boolean writeFile(String filename, String text) {
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(filename);
+ writer.write(text);
+ writer.flush();
+ } catch (IOException e) {
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ return true;
+ } catch (Exception e) {
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Write the given text to a file.
+ *
+ * @param fileName
+ * The target file name.
+ * @param text
+ * The text to write.
+ * @return true if the given text is written successfully to file.
+ */
+ public static boolean writeUTF8File(String filename, String text) {
+ OutputStreamWriter writer = null;
+ FileOutputStream fileOut = null;
+ try {
+ fileOut = new FileOutputStream(filename);
+ writer = new OutputStreamWriter(fileOut, "UTF-8"); //$NON-NLS-1$
+ writer.write(text);
+ writer.flush();
+ fileOut.flush();
+ } catch (IOException e) {
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ return true;
+ } catch (Exception e) {
+ }
+ }
+ if (fileOut != null) {
+ try {
+ fileOut.close();
+ return true;
+ } catch (Exception e) {
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Write the content of the given URI to the given output stream.
+ *
+ * @param uri
+ * The source URI.
+ * @param output
+ * The output stream.
+ */
+ public static void writeFile(String uri, OutputStream output)
+ throws IOException {
+ if (uri == null) {
+ return;
+ }
+
+ InputStream input = null;
+ try {
+ input = NetUtil.getInputStream(uri);
+ int bytesRead;
+ byte[] buf = new byte[4096];
+ while ((bytesRead = input.read(buf, 0, 4096)) > 0) {
+ output.write(buf, 0, bytesRead);
+ }
+ output.flush();
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Write the content of the given URI to the given PrintWriter.
+ *
+ * @param uri
+ * The source URI.
+ * @param writer
+ * The PrintWriter obejct.
+ */
+ public static void writeFile(String uri, PrintWriter pw) throws IOException {
+ if (uri == null) {
+ return;
+ }
+
+ InputStreamReader input = null;
+ try {
+ input = new InputStreamReader(NetUtil.getInputStream(uri));
+ int charsRead;
+ char[] buf = new char[4096];
+ while ((charsRead = input.read(buf, 0, 4096)) > 0) {
+ pw.write(buf, 0, charsRead);
+ }
+ pw.flush();
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Delete all sub-directories and files in the given directory.
+ *
+ * @param dir
+ * The directory containing the sub-directories and files.
+ */
+ public static void delete(File dir) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ File file = files[i];
+ if (file.isFile()) {
+ file.delete();
+ } else {
+ delete(file);
+ }
+ }
+ }
+ dir.delete();
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/NetUtil.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/NetUtil.java
new file mode 100644
index 0000000..f03ceaf
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/NetUtil.java
@@ -0,0 +1,321 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2006 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+* Implements a utility class for managing URLs and URIs.
+*
+* @author Kelvin Low
+* @since 6.0
+*/
+public class NetUtil {
+
+ /**
+ * HTTP URI prefix.
+ */
+ public final static String URI_HTTP_PREFIX = "http://"; //$NON-NLS-1$
+
+ /**
+ * File URI prefix.
+ */
+ public final static String URI_FILE_PREFIX = "file:/"; //$NON-NLS-1$
+
+ /**
+ * HTTP URI prefix size.
+ */
+ public final static int URI_HTTP_PREFIX_SIZE = URI_HTTP_PREFIX.length();
+
+ /**
+ * File URI prefix size.
+ */
+ public final static int URI_FILE_PREFIX_SIZE = URI_FILE_PREFIX.length();
+
+ /**
+ * A table of hex values.
+ */
+ private final static String[] HEX_VALUES = {
+ "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%28", "%29", "%2A", "%2B", "%2C", "%2D", "%2E", "%2F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%38", "%39", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%58", "%59", "%5A", "%5B", "%5C", "%5D", "%5E", "%5F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%78", "%79", "%7A", "%7B", "%7C", "%7D", "%7E", "%7F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$
+ };
+
+ /**
+ * Private constructor to prevent this class from being instantiated. All
+ * methods in this class should be static.
+ */
+ private NetUtil() {
+ }
+
+ /**
+ * Returns the URI for the given file.
+ *
+ * @param file
+ * The input file.
+ * @return The URI for the given file.
+ * @throws MalformedURLException
+ * if an error occur while constructing the URI for the given
+ * file.
+ */
+ public static String getUri(File file) throws MalformedURLException {
+ String url = file.toURL().toExternalForm();
+ StringBuffer strBuf = new StringBuffer();
+ int urlLength = url.length();
+ for (int i = 0; i < urlLength; i++) {
+ char ch = url.charAt(i);
+ switch (ch) {
+ case ' ':
+ strBuf.append("%20"); //$NON-NLS-1$
+ break;
+ default:
+ strBuf.append(ch);
+ break;
+ }
+ }
+ return strBuf.toString();
+ }
+
+ /**
+ * Resolves the given URI using the given the base URI.
+ *
+ * @param uri
+ * The URI to resolve.
+ * @param baseUri
+ * The base URI.
+ * @return A fully formed URI.
+ */
+ public static String resolveUri(String uri, String baseUri) {
+ if (uri == null) {
+ return null;
+ }
+
+ if (uri.startsWith("../")) //$NON-NLS-1$
+ {
+ if (baseUri.endsWith("/")) //$NON-NLS-1$
+ {
+ baseUri = baseUri.substring(0, baseUri.length() - 1);
+ }
+ while (uri.startsWith("../")) //$NON-NLS-1$
+ {
+ uri = uri.substring(3);
+ int index = baseUri.lastIndexOf('/');
+ if (index > 0) {
+ baseUri = baseUri.substring(0, index);
+ }
+ }
+ uri = "/" + uri; //$NON-NLS-1$
+ }
+
+ if (uri.startsWith("/")) //$NON-NLS-1$
+ {
+ return baseUri.endsWith("/") //$NON-NLS-1$
+ ? baseUri + uri.substring(1)
+ : baseUri + uri;
+ }
+
+ if (uri.startsWith(URI_HTTP_PREFIX) || uri.startsWith(URI_FILE_PREFIX)) {
+ return uri;
+ }
+
+ return baseUri.endsWith("/") ? baseUri + uri : baseUri + '/' + uri; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the input stream for the given URI.
+ *
+ * @param uri
+ * The source URI.
+ * @return The input stream for the given URI.
+ * @throw MalformedURLException if a given XML document URI is invalid.
+ * @throw IOException if an I/O error occur while accessing the URI.
+ */
+ public static InputStream getInputStream(String uri)
+ throws MalformedURLException, IOException {
+ if (uri == null) {
+ return null;
+ }
+
+ if (uri.startsWith(URI_HTTP_PREFIX)) {
+ URL url = new URL(uri);
+ return url.openStream();
+ } else if (uri.startsWith(URI_FILE_PREFIX)) {
+ uri = uri.substring(URI_FILE_PREFIX_SIZE);
+ }
+
+ return new FileInputStream(NetUtil.decodeUrl(uri, null));
+ }
+
+ /**
+ * Returns the Java string represention (encoded in UTF-16) of the given URL
+ * (encoded in the given encoding and ASCII-escaped).
+ *
+ * @param url
+ * The URL to decode.
+ * @param encoding
+ * The encoding of the URL.
+ * @return The Java UTF-16 string respresentation.
+ * @throws IllegalArgumentException
+ * if the given URL contain improperly escaped characters.
+ */
+ public static String decodeUrl(String url, String encoding) {
+ int len = url.length();
+
+ if (url == null || len == 0) {
+ return url;
+ }
+
+ // Unescape the url.
+ StringBuffer strBuf = new StringBuffer();
+ for (int i = 0; i < len; i++) {
+ char ch = url.charAt(i);
+ switch (ch) {
+ case '+':
+ strBuf.append(' ');
+ break;
+ case '%':
+ try {
+ strBuf.append((char) Integer.parseInt(url.substring(i + 1,
+ i + 3), 16));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException();
+ }
+ i += 2;
+ break;
+ default:
+ strBuf.append(ch);
+ break;
+ }
+ }
+
+ // Convert the un-escaped byte values to Java UTF-16 string.
+ String result = strBuf.toString();
+ if (encoding != null) {
+ try {
+ byte[] bytes = result.getBytes("8859_1"); //$NON-NLS-1$
+ result = new String(bytes, encoding);
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the ASCII-escaped representation (encoded in the specified
+ * encoding) of the given URL (encoded in UTF-16).
+ *
+ * @param url
+ * The URL to encode.
+ * @param encoding
+ * The encoding of the URL.
+ * @return the ASCII-escaped respresentation.
+ * @throws IllegalArgumentException
+ * if the given URL contain improperly escaped characters.
+ * @throws UnsupportedEncodingException
+ * if the given coding is unsupport.
+ */
+ public static String encodeUrl(String url, String encoding)
+ throws UnsupportedEncodingException {
+ int len = url.length();
+
+ if (url == null || len == 0) {
+ return url;
+ }
+
+ StringBuffer result = new StringBuffer();
+
+ byte[] bytes = url.getBytes(encoding);
+ for (int i = 0; i < bytes.length; i++) {
+ char ch = (char) bytes[i];
+
+ if (ch >= 'a' && ch <= 'z') {
+ result.append(ch);
+ } else if (ch >= 'A' && ch <= 'Z') {
+ result.append(ch);
+ } else if (ch >= '0' && ch <= '9') {
+ result.append(ch);
+ } else {
+ switch (ch) {
+ case '-':
+ case '_':
+ case '.':
+ case '!':
+ case '~':
+ case '*':
+ case '\'':
+ case '(':
+ case ')':
+ result.append(ch);
+ break;
+ default:
+ result.append(HEX_VALUES[ch & 0xFF]);
+ break;
+ }
+ }
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Returns the ASCII-escaped representation of the given file URL.
+ *
+ * @param fileURL
+ * The file URL to encode.
+ * @return the ASCII-escaped respresentation.
+ */
+ public static String encodeFileUrl(String fileURL) {
+ String url = fileURL;
+ StringBuffer strBuf = new StringBuffer();
+ int urlLength = url.length();
+ for (int i = 0; i < urlLength; i++) {
+ char ch = url.charAt(i);
+ switch (ch) {
+ case ' ':
+ strBuf.append("%20"); //$NON-NLS-1$
+ break;
+ default:
+ strBuf.append(ch);
+ break;
+ }
+ }
+ return strBuf.toString();
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/StrUtil.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/StrUtil.java
new file mode 100644
index 0000000..08d4608
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/StrUtil.java
@@ -0,0 +1,482 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2006 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.utils;
+
+import java.util.List;
+import com.ibm.icu.util.StringTokenizer;
+
+/**
+ * Implements a utility class for managing strings.
+ *
+ * @author Kelvin Low
+ * @since 6.0
+ */
+public class StrUtil {
+
+ // Array of hex digits.
+ private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ /**
+ * Private constructor to prevent this class from being instantiated. All
+ * methods in this class should be static.
+ */
+ private StrUtil() {
+ }
+
+ /**
+ * Is the given string a null string?
+ * <p>
+ * A null string is defined as one that has a empty reference (i.e. = null)
+ * or has zero length.
+ *
+ * @param str
+ * The test string.
+ * @return true if the the given string is a null string.
+ */
+ public static boolean isNull(String str) {
+ return str == null || str.length() == 0;
+ }
+
+ /**
+ * Is the given string a blank string?
+ * <p>
+ * A blank string is defined as one that has a empty reference (i.e. = null)
+ * or has zero length after the leading and trailing space characters are
+ * trimmed.
+ *
+ * @param str
+ * The test string.
+ * @return true if the the given string is a blank string.
+ */
+ public static boolean isBlank(String str) {
+ return str == null || str.trim().length() == 0;
+ }
+
+ /**
+ * Is the given string an ASCII string?
+ *
+ * @param str
+ * The test string.
+ * @return true if the the given string is an ASCII string.
+ */
+ public static boolean isAscii(String str) {
+ int len = (str == null) ? 0 : str.length();
+ for (int i = 0; i < len; i++) {
+ if (str.charAt(i) > 0x007E) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Removes the leading and trailing space characters (' ') from the given
+ * string.
+ *
+ * @param str
+ * The source string.
+ * @return A string with no leading and trailing space characters.
+ */
+ public static String trim(String str) {
+ return str == null ? null : str.trim();
+ }
+
+ /**
+ * Removes white space characters ('\t', '\n', ' ') from the given string.
+ *
+ * @param str
+ * The source string.
+ * @return A string with white space characters removed.
+ */
+ public static String removeWhiteSpaceChars(String str) {
+ int len = (str == null) ? 0 : str.length();
+ for (int i = 0; i < len; i++) {
+ switch (str.charAt(i)) {
+ case '\t':
+ case '\n':
+ case ' ':
+ break;
+
+ default:
+ return str;
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Removes end-of-line characters from the given string.
+ *
+ * @param str
+ * The source string.
+ * @return A string with no end-of-line characters.
+ */
+ public static String removeEndOfLineChars(String str) {
+ if (isNull(str)) {
+ return str;
+ }
+
+ String lineSep = FileUtil.LINE_SEP;
+ int lineSepSize = FileUtil.LINE_SEP.length();
+
+ while (str.endsWith(lineSep)) {
+ str = str.substring(0, str.length() - lineSepSize);
+ }
+ return str;
+ }
+
+ /**
+ * Removes the given leading and trailing characters from the given string.
+ *
+ * @param str
+ * The source string.
+ * @param chars
+ * The characters to removed.
+ * @return A string with stripped off the given leading and trailing
+ * characters.
+ */
+ public static String removeChars(String str, String chars) {
+ if (isNull(str)) {
+ return str;
+ }
+
+ int sizeOfChars = chars.length();
+
+ while (str.startsWith(chars)) {
+ str = str.substring(sizeOfChars);
+ }
+ while (str.endsWith(chars)) {
+ str = str.substring(0, str.length() - sizeOfChars);
+ }
+
+ return str;
+ }
+
+ /**
+ * Splits the given strings into an array of tokens based on the given
+ * separators.
+ *
+ * @param str
+ * The source string.
+ * @param sep
+ * The string separators.
+ * @param count
+ * The number of tokens to return.
+ * @return An array of string tokens.
+ */
+ public static String[] split(String str, String sep, int count) {
+ if (str == null || count == 0 || count < -1) {
+ return null;
+ }
+
+ StringTokenizer tok = new StringTokenizer(str, sep, count == -1 ? false
+ : true);
+
+ if (count == -1) {
+ count = tok.countTokens();
+ }
+
+ String[] result = new String[count];
+ int i = 0;
+ while (tok.hasMoreTokens()) {
+ String t = tok.nextToken();
+ if (i < count) {
+ if ((t.length() == 1) && (sep.indexOf(t) != -1)) {
+ continue;
+ }
+ result[i++] = t;
+ } else {
+ result[count - 1] += t;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Splits the given strings into an array of tokens based on the given
+ * separators.
+ *
+ * @param str
+ * The source string.
+ * @param sep
+ * The string separators.
+ * @return An array of string tokens.
+ */
+ public static String[] split(String str, String sep) {
+ return split(str, sep, -1);
+ }
+
+ /**
+ * Returns true if a the given sub-string matches a string token in the
+ * delimited source string.
+ *
+ * @param str
+ * The delimited source string.
+ * @param strSep
+ * The separators that delimit the source string.
+ * @param substr
+ * The delimited sub-string.
+ * @return true if the given substr is found in the source string.
+ */
+ public static boolean contains(String str, String strSep, String substr) {
+ if (str == null || strSep == null || substr == null) {
+ return false;
+ }
+ String[] strs = split(str, strSep, -1);
+ if (strs != null) {
+ for (int i = 0; i < strs.length; i++) {
+ if (strs[i] != null && strs[i].equals(substr)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if a string token in the given sub-string matches a string
+ * token in the delimited source string.
+ *
+ * @param str
+ * The delimited source string.
+ * @param strSep
+ * The separators that delimit the source string.
+ * @param substr
+ * Tthe delimited sub-string.
+ * @param subStrSep
+ * The separators that delimit the sub-string.
+ * @return true if the given substr is found in the source string.
+ */
+ public static boolean contains(String str, String strSep, String substr,
+ String subStrSep) {
+ if (str == null || strSep == null || substr == null
+ || subStrSep == null) {
+ return false;
+ }
+
+ String[] strs = split(str, strSep, -1);
+ String[] substrs = split(substr, subStrSep, -1);
+
+ if (strs != null && substrs != null) {
+ for (int i = 0; i < strs.length; i++) {
+ if (strs[i] != null) {
+ for (int j = 0; j < substrs.length; j++) {
+ if (substrs[j] != null && substrs[j].equals(strs[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Replaces a substring within a string with another string. This just
+ * replaces the first occurrence of the string.
+ *
+ * @param str
+ * The source string.
+ * @param src
+ * The substring to replace.
+ * @param tgt
+ * The substring to use for the replacement.
+ * @return The result string.
+ */
+ public static String replace(String str, String src, String tgt) {
+ if (isNull(str) || isNull(src)) {
+ return str;
+ }
+
+ String tmpStr = str;
+ int index;
+ while ((index = tmpStr.indexOf(src)) != -1) {
+ tmpStr = tmpStr.substring(0, index) + tgt
+ + tmpStr.substring(index + src.length());
+ }
+ return tmpStr;
+ }
+
+ /**
+ * Converts all characters in a string to the given character.
+ *
+ * @param str
+ * The source string.
+ * @param ch
+ * The target character.
+ * @return The converted string.
+ */
+ public static String convert(String str, char ch) {
+ if (isNull(str)) {
+ return str;
+ }
+
+ int len = str.length();
+ StringBuffer buf = new StringBuffer(len + 1);
+ for (int i = 0; i < len; i++) {
+ buf.append(ch);
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Replaces the given set of characters in the given string with a target
+ * character.
+ *
+ * @param str
+ * The source string.
+ * @param srcChars
+ * The set of characters to replace.
+ * @param tgtChar
+ * The target character.
+ * @return The converted string.
+ */
+ public static String replace(String str, String srcChars, char tgtChar) {
+ for (int i = 0; i < srcChars.length(); i++) {
+ str = str.replace(srcChars.charAt(i), tgtChar);
+ }
+ return str;
+ }
+
+ /**
+ * Gets the integer value of the given string.
+ *
+ * @param str
+ * The source string.
+ * @param defValue
+ * The default integer value.
+ * @param The
+ * integer value of the given string.
+ */
+ public static int getIntValue(String str, int defValue) {
+ if (StrUtil.isBlank(str)) {
+ return defValue;
+ }
+
+ try {
+ return Integer.parseInt(str);
+ } catch (NumberFormatException e) {
+ return defValue;
+ }
+ }
+
+ /**
+ * Returns an array of bytes representing the UTF-8 encoding of the given
+ * string.
+ *
+ * @param str
+ * The source string.
+ * @return A byte array containing the UTF-8 encoding of the given string.
+ */
+ public static byte[] getUTF8Bytes(String str) {
+ char[] c = str.toCharArray();
+ int len = c.length;
+ int count = 0;
+ for (int i = 0; i < len; i++) {
+ int ch = c[i];
+ if (ch <= 0x7f) {
+ count++;
+ } else if (ch <= 0x7ff) {
+ count += 2;
+ } else {
+ count += 3;
+ }
+ }
+
+ byte[] b = new byte[count];
+ int off = 0;
+ for (int i = 0; i < len; i++) {
+ int ch = c[i];
+ if (ch <= 0x7f) {
+ b[off++] = (byte) ch;
+ } else if (ch <= 0x7ff) {
+ b[off++] = (byte) ((ch >> 6) | 0xc0);
+ b[off++] = (byte) ((ch & 0x3f) | 0x80);
+ } else {
+ b[off++] = (byte) ((ch >> 12) | 0xe0);
+ b[off++] = (byte) (((ch >> 6) & 0x3f) | 0x80);
+ b[off++] = (byte) ((ch & 0x3f) | 0x80);
+ }
+ }
+ return b;
+ }
+
+ /**
+ * Returns the hexidecimal character representation for the given integer.
+ *
+ * @param value
+ * The integer value.
+ * @return The hex representation.
+ */
+ private static char toHex(int value) {
+ return HEX_DIGITS[(value & 0xF)];
+ }
+
+ /**
+ * Returns the escaped Unicode string representation of the given Java
+ * string.
+ *
+ * @param str
+ * The Java string (encoded in UTF-16).
+ * @param skipAscii
+ * If true, avoid escaping the ASCII characters.
+ * @return The escaped Unicode string representation.
+ */
+ public static String toEscapedUnicode(String str, boolean skipAscii) {
+ int len = str.length();
+ StringBuffer result = new StringBuffer(len * 2);
+
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+
+ if (skipAscii && ch < 0x007E) {
+ result.append(ch);
+ } else {
+ result.append("\\u"); //$NON-NLS-1$
+ result.append(toHex((ch >> 12) & 0xF));
+ result.append(toHex((ch >> 8) & 0xF));
+ result.append(toHex((ch >> 4) & 0xF));
+ result.append(toHex(ch & 0xF));
+ }
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Convert List to String Array
+ *
+ * @param list
+ * @return String[]
+ */
+ public static String[] convertListToStrArray(List list) {
+ if (list != null) {
+ int cnt = list.size();
+ String[] strArray = new String[cnt];
+
+ for (int i = 0; i < cnt; i++) {
+ String str = (String) list.get(i);
+ strArray[i] = new String(str);
+ }
+ return strArray;
+ } else {
+ return null;
+ }
+ }
+
+ public static String convertFirstLetterCase(String s, String[] keyWords) {
+ StringBuffer sb = new StringBuffer(s.substring(0, 1).toUpperCase()
+ + s.substring(1).toLowerCase());
+ int foundIndex;
+ for (int i = 0; i < keyWords.length; i++) {
+ if ((foundIndex = s.indexOf(keyWords[i].toLowerCase(), 1)) != -1) {
+ sb.replace(foundIndex, foundIndex + keyWords[i].length(),
+ keyWords[i]);
+ }
+ }
+ //System.out.println(sb.toString());
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/UNCUtil.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/UNCUtil.java
new file mode 100644
index 0000000..2de53ab
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/UNCUtil.java
@@ -0,0 +1,305 @@
+package org.eclipse.epf.web.search.utils;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+
+public class UNCUtil {
+ public static final String UNC_FILE_PREFIX = "file:/";
+ public static final String ALTERNATE_UNC_FILE_PREFIX = "file://";
+ public static final String NETSCAPE_UNC_FILE_PREFIX = "file:///";
+ public static final String UNC_FILE_ONLY = "file:";
+ public static final String UNC_SEPARATOR = "/";
+
+
+ /**
+ * Accounts for netscape unc file prefix. Converts to standard one.
+ * If not Netscape, nothing changes.
+ */
+ public static String handleNetscapeFilePrefix(String filename)
+ {
+ String convertedName = null;
+
+ if (filename.startsWith(NETSCAPE_UNC_FILE_PREFIX))
+ {
+ convertedName =
+ ALTERNATE_UNC_FILE_PREFIX
+ + filename.substring(
+ NETSCAPE_UNC_FILE_PREFIX.length(),
+ filename.length());
+ }
+ else
+ {
+ convertedName = filename;
+ }
+
+ return (convertedName);
+ }
+
+ /**
+ * Handles URL paths for Mozilla (and other browsers) over UNC.
+ */
+ public static URL handleURLForUNC(URL originalUrl)
+ {
+ // handle special case for Mozilla over UNC
+ URL newUrl = null;
+ try
+ {
+ if (originalUrl.toString().startsWith("file://"))
+ {
+ // change "file://" to "file://///"
+ String extractedString = originalUrl.toString().substring(5);
+ newUrl = new URL("file", "", "///" + extractedString);
+ }
+ else
+ {
+ newUrl = originalUrl;
+ }
+ }
+ catch (java.net.MalformedURLException mue)
+ {
+ newUrl = originalUrl;
+ }
+
+ return (newUrl);
+ }
+
+ /**
+ * Converts the UNC file to a regular, platform-dependent one.
+ */
+ public static String convertFilename(String filename)
+ {
+ String convertedName = null;
+
+ // remove any URL prefixes
+ String tempName = null;
+ if (filename.startsWith(UNC_FILE_PREFIX))
+ {
+ tempName = filename.substring(UNC_FILE_PREFIX.length(), filename.length());
+ int index = tempName.indexOf(":");
+ if (index == -1)
+ {
+ // on Unix, add separator back to first character
+ tempName = UNC_SEPARATOR + tempName;
+ }
+ }
+ else
+ {
+ tempName = filename;
+ }
+
+ // convert any UNC separators to the system default one
+ convertedName =
+ tempName.replace(UNC_SEPARATOR.charAt(0), File.separator.charAt(0));
+
+ return (convertedName);
+ }
+
+ /**
+ * Converts the filename to a UNC filename.
+ */
+ public static String convertFilenameToUNC(String filename)
+ {
+ // convert any UNC separators to the system default one
+ String convertedName =
+ filename.replace(File.separator.charAt(0), UNC_SEPARATOR.charAt(0));
+ String finalName = convertFileSeparator(convertedName);
+ return (finalName);
+ }
+
+ /**
+ * Converts the URL to one which can that matches a UNC convention.
+ */
+ public static String convertToUNC(String url)
+ {
+ String convertedUrl = null;
+ if (url.startsWith(ALTERNATE_UNC_FILE_PREFIX))
+ {
+ convertedUrl =
+ UNC_FILE_PREFIX
+ + url.substring(ALTERNATE_UNC_FILE_PREFIX.length(), url.length());
+ }
+ else
+ {
+ convertedUrl = url;
+ }
+ return (convertedUrl);
+
+ }
+
+ /**
+ * Removes the "%20" that is used by some browsers for spaces
+ */
+ public static String convertFileSpacing(String filename)
+ {
+ // now remove any "%20"
+ int start = 0;
+ String newFilename = "";
+ while (start < filename.length())
+ {
+ int index = filename.indexOf("%20", start);
+ if (index == -1)
+ {
+ index = filename.length();
+ }
+ newFilename += filename.substring(start, index);
+ newFilename += " ";
+ start = index + 3;
+ }
+
+ newFilename = newFilename.trim();
+
+ return (newFilename);
+ }
+
+ /**
+ * Removes the "%5C" that is used by some browsers for file separator.
+ */
+ public static String convertFileSeparator(String filename)
+ {
+ // remove any "%5C"
+ int start = 0;
+ String newFilename = "";
+ while (start < filename.length())
+ {
+ int index = filename.indexOf("%5C", start);
+ if (index == -1)
+ {
+ //index = filename.length();
+ newFilename = filename.trim();
+ break;
+ }
+ newFilename += filename.substring(start, index);
+ newFilename += UNC_SEPARATOR;
+ start = index + 3;
+ }
+
+ newFilename = newFilename.trim();
+
+ // also if file separator equals unc separator, remove any Windows
+ // specific "\"
+ String windowsFileSeparator = "\\";
+ if (!File.separator.equals(windowsFileSeparator)
+ && File.separator.equals(UNC_SEPARATOR))
+ {
+ // on Unix
+ newFilename =
+ newFilename.replace(
+ windowsFileSeparator.charAt(0),
+ UNC_SEPARATOR.charAt(0));
+ }
+ return (newFilename);
+ }
+
+ /**
+ * Retrieves the file names from the specified directory
+ * that matches the given suffix. An example of a
+ * suffix is ".dat".
+ */
+ public static Vector getFileList(String directory, String suffix)
+ {
+ if (directory.startsWith("http"))
+ {
+ // remote directory, use this instead
+ return (getFileListFromRemote(directory, suffix));
+ }
+
+ String tempDir = UNCUtil.convertFilename(directory);
+ File documentDirectory = new File(UNCUtil.convertFileSpacing(tempDir));
+ String[] fileNameList = documentDirectory.list();
+
+ // now parse and only take those that end with the proper suffix
+ Vector finalList = new Vector();
+ for (int i = 0; i < fileNameList.length; i++)
+ {
+ if (fileNameList[i].endsWith(suffix))
+ {
+ finalList.addElement(fileNameList[i]);
+ }
+ }
+
+ return (finalList);
+ }
+
+ /**
+ * Retrieves the applicable default rup files from remote directory.
+ */
+ private static Vector getFileListFromRemote(String directory, String suffix)
+ {
+ Vector filenames = new Vector();
+ try
+ {
+ // get the listing using a URL
+ URL remoteUrl = new URL(directory);
+ InputStream inStream = remoteUrl.openStream();
+ StringBuffer result = new StringBuffer();
+ int c;
+ while ((c = inStream.read()) != -1)
+ {
+ result.append((char) c);
+ }
+ inStream.close();
+
+ // convert string to upper case to handle multiple server types such as Apache
+ String directoryResult = result.toString();
+ directoryResult = directoryResult.replaceAll("href", "HREF");
+ directoryResult = directoryResult.replaceAll("</a", "</A");
+ directoryResult = directoryResult.replaceAll("<tt>", "");
+ directoryResult = directoryResult.replaceAll("</tt>", "");
+ directoryResult = directoryResult.replaceAll("<TT>", "");
+ directoryResult = directoryResult.replaceAll("</TT>", "");
+
+ // parse the content
+ //StringTokenizer lineTokenizer = new StringTokenizer( result.toString() );
+ StringTokenizer lineTokenizer = new StringTokenizer(directoryResult);
+ Vector lines = new Vector();
+ try
+ {
+ while (true)
+ {
+ lineTokenizer.nextToken("REF");
+ lineTokenizer.nextToken("\"");
+ String line = lineTokenizer.nextToken("\"");
+
+ // strip out "</A"; needed this because StringTokenizer
+ // has problems parsing filenames that being with "A"
+ int index = line.indexOf("</A");
+ if (index != -1 && index != 0)
+ {
+ String filename = line.substring(0, index);
+ lines.addElement(filename);
+ }
+ else
+ {
+ lines.addElement(line);
+ }
+ }
+ }
+ catch (NoSuchElementException ne)
+ {
+ // do nothing, end of content
+ }
+
+ // parse each line
+ for (int i = 0; i < lines.size(); i++)
+ {
+ String line = (String) lines.elementAt(i);
+
+ if (line.endsWith(suffix))
+ {
+ // we want this
+ filenames.addElement(line);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return (filenames);
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/XMLUtil.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/XMLUtil.java
new file mode 100644
index 0000000..239d02b
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/XMLUtil.java
@@ -0,0 +1,562 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2006 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXParseException;
+
+/**
+* Utility class for processing XML documents.
+*
+* @author Kelvin Low
+* @author Jinhua Xi
+* @since 7.0
+*/
+public class XMLUtil {
+
+ /**
+ * XML declaration.
+ */
+ public final static String XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; //$NON-NLS-1$
+
+ /**
+ * XML Escape characters.
+ */
+ public final static String XML_AMP = "&"; //$NON-NLS-1$
+
+ public final static String XML_APOS = "'"; //$NON-NLS-1$
+
+ public final static String XML_CR = " "; //$NON-NLS-1$
+
+ public final static String XML_GT = ">"; //$NON-NLS-1$
+
+ public final static String XML_LT = "<"; //$NON-NLS-1$
+
+ public final static String XML_LF = " "; //$NON-NLS-1$
+
+ public final static String XML_QUOT = """; //$NON-NLS-1$
+
+ public final static String XML_TAB = "	"; //$NON-NLS-1$
+
+ private static final String CRLF = "\r\n"; //$NON-NLS-1$
+
+ private static final byte[] CRLF_BYTES = CRLF.getBytes();
+
+ /**
+ * Private constructor to prevent this class from being instantiated. All
+ * methods in this class should be static.
+ */
+ private XMLUtil() {
+ }
+
+ /**
+ * Clones the given DOM node into the given DOM document.
+ *
+ * @param node
+ * The DOM node to clone.
+ * @param doc
+ * The target DOM document.
+ * @return The cloned node in the target DOM document.
+ */
+ public static Node cloneNode(Node node, Document doc) {
+ Node clone = null;
+ switch (node.getNodeType()) {
+ case Node.ELEMENT_NODE:
+ clone = doc.createElement(node.getNodeName());
+ NamedNodeMap attrs = node.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Node attrNode = attrs.item(i);
+ Attr attrClone = doc.createAttribute(attrNode.getNodeName());
+ attrClone.setNodeValue(attrNode.getNodeValue());
+ ((Element) clone).setAttributeNode(attrClone);
+ }
+
+ // Iterate through each child nodes.
+ NodeList childNodes = node.getChildNodes();
+ if (childNodes != null) {
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node childNode = childNodes.item(i);
+ Node childClone = cloneNode(childNode, doc);
+ clone.appendChild(childClone);
+ }
+ }
+ break;
+
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ clone = doc.createTextNode(node.getNodeName());
+ clone.setNodeValue(node.getNodeValue());
+ break;
+ }
+ return clone;
+ }
+
+ /**
+ * Escapes the given string to make it XML parser friendly.
+ *
+ * @param str
+ * The source string.
+ * @return The escaped string.
+ */
+ public static String escape(String str) {
+ if (str == null || str.length() == 0)
+ return ""; //$NON-NLS-1$
+ StringBuffer sb = new StringBuffer();
+ int len = str.length();
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+ switch (ch) {
+ case '<':
+ sb.append(XML_LT);
+ break;
+ case '>':
+ sb.append(XML_GT);
+ break;
+ case '&':
+ sb.append(XML_AMP);
+ break;
+ case '"':
+ sb.append(XML_QUOT);
+ break;
+ case '\'':
+ sb.append(XML_APOS);
+ break;
+ case '\r':
+ sb.append(XML_CR);
+ break;
+ case '\n':
+ sb.append(XML_LF);
+ break;
+ default:
+ sb.append(ch);
+ break;
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Escapes the given string to make it XML parser friendly.
+ *
+ * @param str
+ * The source string.
+ * @param ignoreCRLF
+ * If true, do not escape the CR and LF characters.
+ * @return The escaped string.
+ */
+ public static String escape(String str, boolean ignoreCRLF) {
+ if (str == null || str.length() == 0)
+ return ""; //$NON-NLS-1$
+ StringBuffer sb = new StringBuffer();
+ int len = str.length();
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+ switch (ch) {
+ case '<':
+ sb.append(XML_LT);
+ break;
+ case '>':
+ sb.append(XML_GT);
+ break;
+ case '&':
+ sb.append(XML_AMP);
+ break;
+ case '"':
+ sb.append(XML_QUOT);
+ break;
+ case '\'':
+ sb.append(XML_APOS);
+ break;
+ case '\r':
+ if (ignoreCRLF)
+ sb.append(ch);
+ else
+ sb.append(XML_CR);
+ break;
+ case '\n':
+ if (ignoreCRLF)
+ sb.append(ch);
+ else
+ sb.append(XML_LF);
+ break;
+ default:
+ sb.append(ch);
+ break;
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Unescapes the given XML string.
+ *
+ * @param str
+ * The source string.
+ * @return The escaped string.
+ */
+ public static String unescape(String str) {
+ if (str == null || str.length() == 0)
+ return ""; //$NON-NLS-1$
+ StringBuffer sb = new StringBuffer();
+ int len = str.length();
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+ switch (ch) {
+ case '&':
+ if (str.startsWith(XML_LT, i)) {
+ sb.append('<');
+ i += 3;
+ } else if (str.startsWith(XML_GT, i)) {
+ sb.append('>');
+ i += 3;
+ } else if (str.startsWith(XML_AMP, i)) {
+ sb.append('&');
+ i += 4;
+ } else if (str.startsWith(XML_QUOT, i)) {
+ sb.append('"');
+ i += 5;
+ } else if (str.startsWith(XML_APOS, i)) {
+ sb.append("\'"); //$NON-NLS-1$
+ i += 5;
+ } else if (str.startsWith(XML_CR, i)) {
+ sb.append('\r');
+ i += 4;
+ } else if (str.startsWith(XML_LF, i)) {
+ sb.append('\n');
+ i += 4;
+ } else {
+ sb.append(ch);
+ }
+ break;
+ default:
+ sb.append(ch);
+ break;
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Writes the content of the given DOM document to the output stream.
+ *
+ * @param xmlDoc
+ * The DOM document.
+ * @param output
+ * The output stream.
+ * @throws IOException
+ * if an I/O error occur while accessing the output stream.
+ */
+ public static void writeDocument(Document xmlDoc, OutputStream output)
+ throws IOException {
+ DataOutputStream out = new DataOutputStream(output);
+ writeNode(xmlDoc, "", out); //$NON-NLS-1$
+ out.flush();
+ }
+
+ /**
+ * Writes the content of the given DOM document to the PrintWriter.
+ *
+ * @param xmlDoc
+ * The DOM document.
+ * @param pw
+ * The PrintWriter object.
+ * @throws IOException
+ * if an I/O error occur while accessing the output stream.
+ */
+ public static void writeDocument(Document xmlDoc, PrintWriter pw)
+ throws IOException {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ DataOutputStream out = new DataOutputStream(os);
+ writeNode(xmlDoc, "", out); //$NON-NLS-1$
+ out.flush();
+ // TODO: Investigate whether encoding should be specified?
+ String s = os.toString();
+ pw.write(s);
+ pw.flush();
+ }
+
+ /**
+ * Saves the content of the given DOM document to file.
+ *
+ * @param xmlDoc
+ * The DOM document.
+ * @param xmlFile
+ * The XML file.
+ * @throws IOException
+ * if an I/O error occur while accessing the output stream.
+ */
+ public static void saveDocument(Document xmlDoc, String xmlFile)
+ throws IOException {
+ DataOutputStream out = new DataOutputStream(new FileOutputStream(
+ xmlFile));
+ writeNode(xmlDoc, "", out); //$NON-NLS-1$
+ out.flush();
+ out.close();
+ }
+
+ /**
+ * Saves the given XML string to the given file.
+ *
+ * @param xmlStr
+ * The XML string.
+ * @param xmlFile
+ * The XML file.
+ * @throws IOException
+ * if an I/O error occur while accessing the output stream.
+ */
+ public static void saveDocument(String xmlStr, String xmlFile)
+ throws IOException {
+ DataOutputStream out = new DataOutputStream(new FileOutputStream(
+ xmlFile));
+ out.write(xmlStr.getBytes());
+ out.flush();
+ out.close();
+ }
+
+ /**
+ * Writes the given DOM tree node to the given output stream.
+ *
+ * @param node
+ * The DOM node.
+ * @param indent
+ * The string indentation (containing space characters).
+ * @param out
+ * The output stream.
+ * @throws IOException
+ * if an I/O error occur while accessing the output stream.
+ */
+ private static void writeNode(Node node, String indent, DataOutputStream out)
+ throws IOException {
+ String text;
+
+ switch (node.getNodeType()) {
+ case Node.DOCUMENT_NODE:
+ // Write the XML file signature.
+ out.write(StrUtil.getUTF8Bytes(XML_DECLARATION));
+ out.write(CRLF_BYTES);
+
+ // Iterate through each child nodes.
+ NodeList nodes = node.getChildNodes();
+ if (nodes != null) {
+ for (int i = 0; i < nodes.getLength(); i++) {
+ writeNode(nodes.item(i), "", out); //$NON-NLS-1$
+ }
+ }
+ break;
+
+ case Node.ELEMENT_NODE:
+ String name = node.getNodeName();
+ out.write(StrUtil.getUTF8Bytes(indent + "<" + name)); //$NON-NLS-1$
+ NamedNodeMap attrs = node.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Node attrNode = attrs.item(i);
+ out.write(StrUtil.getUTF8Bytes(" " + attrNode.getNodeName() //$NON-NLS-1$
+ + "=\"" + escape(attrNode.getNodeValue()) + "\"")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ out.write(StrUtil.getUTF8Bytes(">")); //$NON-NLS-1$
+ out.write(CRLF_BYTES);
+
+ // Iterate through each child nodes.
+ NodeList childNodes = node.getChildNodes();
+ if (childNodes != null) {
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ writeNode(childNodes.item(i), indent, out);
+ }
+ }
+ out.write(StrUtil.getUTF8Bytes(indent + "</" + name + ">")); //$NON-NLS-1$ //$NON-NLS-2$
+ out.write(CRLF_BYTES);
+
+ break;
+
+ case Node.TEXT_NODE:
+ text = StrUtil.removeWhiteSpaceChars(node.getNodeValue());
+ if (text.length() > 0) {
+ out.write(StrUtil.getUTF8Bytes(escape(text)));
+ }
+ break;
+
+ case Node.CDATA_SECTION_NODE:
+ text = StrUtil.removeWhiteSpaceChars(node.getNodeValue());
+ if (text.length() > 0) {
+ out.write(StrUtil.getUTF8Bytes("<![CDATA[")); //$NON-NLS-1$
+ out.write(StrUtil.getUTF8Bytes(text));
+ out.write(StrUtil.getUTF8Bytes("]]>")); //$NON-NLS-1$
+ out.write(CRLF_BYTES);
+ }
+ break;
+
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ out.write(StrUtil.getUTF8Bytes("<?" + node.getNodeName() //$NON-NLS-1$
+ + " " + node.getNodeValue() + "?>")); //$NON-NLS-1$ //$NON-NLS-2$
+ out.write(CRLF_BYTES);
+ break;
+
+ case Node.ENTITY_REFERENCE_NODE:
+ out.write(StrUtil.getUTF8Bytes("&" + node.getNodeName() + ";")); //$NON-NLS-1$ //$NON-NLS-2$
+ break;
+ }
+ }
+
+ /**
+ * Returns the file location where the given SAX exception occurred.
+ *
+ * @param e
+ * The SAX parse exception.
+ * @return A string containing the file location where the exception
+ * occurred.
+ */
+ public static String getLocationOfException(SAXParseException e) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("row "); //$NON-NLS-1$
+ sb.append(e.getLineNumber());
+ sb.append(", col "); //$NON-NLS-1$
+ sb.append(e.getColumnNumber());
+
+ String systemId = e.getSystemId();
+ if (systemId != null) {
+ int index = systemId.lastIndexOf('/');
+ if (index != -1) {
+ systemId = systemId.substring(index + 1);
+ }
+ sb.append(" of XML document "); //$NON-NLS-1$
+ sb.append(systemId);
+ }
+
+ return sb.toString();
+ }
+
+ public static Document loadXml(File file) throws Exception {
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory
+ .newInstance();
+ DocumentBuilder builder = builderFactory.newDocumentBuilder();
+
+ return builder.parse(file);
+ }
+
+ public static Document createDocument() throws Exception {
+ DocumentBuilderFactory builderFactory = DocumentBuilderFactory
+ .newInstance();
+ DocumentBuilder builder = builderFactory.newDocumentBuilder();
+ return builder.newDocument();
+ }
+
+ /**
+ * text of a leaf node, without child element
+ *
+ * @param tag
+ * @return String
+ */
+ public static String getNodeText(Element tag) {
+ String text = tag.toString();
+ int i = text.indexOf(">"); //$NON-NLS-1$
+ int j = text.lastIndexOf("</"); //$NON-NLS-1$
+ if (i < 0 || j < 0 || j < i) {
+ return ""; //$NON-NLS-1$
+ }
+
+ return text.substring(i + 1, j);
+ }
+
+ public static String getChildText(Element tag, String childTagName) {
+ Element child = getFirstChild(tag, childTagName);
+ if (child != null) {
+ return getNodeText(child);
+ }
+
+ return ""; //$NON-NLS-1$
+ }
+
+ public static Element getFirstChild(Element tag, String childTagName) {
+ NodeList nodes = tag.getElementsByTagName(childTagName);
+ if (nodes == null || nodes.getLength() == 0) {
+ return null;
+ }
+
+ return (Element) nodes.item(0);
+ }
+
+ /**
+ * iterator of all the children of the element
+ *
+ * @param tag
+ * @return Iterator
+ */
+ public static Iterator childIterator(Element tag) {
+ NodeList nodes = tag.getChildNodes();
+
+ // NodeList contains no Element nodes such as text nodes, ignore those
+ List elements = new ArrayList();
+ if (nodes != null) {
+ int size = nodes.getLength();
+ for (int i = 0; i < size; i++) {
+ Node node = nodes.item(i);
+ if (node instanceof Element) {
+ elements.add(node);
+ }
+ }
+ }
+
+ return elements.iterator();
+ }
+
+ private static class NodeIterator implements Iterator {
+ int currentIndex = -1;
+
+ int size = 0;
+
+ NodeList nodes = null;
+
+ public NodeIterator(NodeList nodes) {
+ this.nodes = nodes;
+ if (nodes != null)
+ size = nodes.getLength();
+ }
+
+ public void remove() {
+ // Do nothing, this is a readonly iterator.
+ }
+
+ public boolean hasNext() {
+ return currentIndex + 1 < size;
+ }
+
+ public Object next() {
+ if (hasNext()) {
+ return nodes.item(++currentIndex);
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * iterator of all the children of the element
+ *
+ * @param tag
+ * @return Iterator
+ */
+ public static Iterator childIterator(Element tag, String childTagName) {
+ NodeList nodes = tag.getElementsByTagName(childTagName);
+ return new NodeIterator(nodes);
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/XSLTProcessor.java b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/XSLTProcessor.java
new file mode 100644
index 0000000..c46beb9
--- /dev/null
+++ b/org.eclipse.epf.web.search/src/org/eclipse/epf/web/search/utils/XSLTProcessor.java
@@ -0,0 +1,403 @@
+//------------------------------------------------------------------------------
+//Copyright (c) 2004, 2006 IBM Corporation. All Rights Reserved.
+//------------------------------------------------------------------------------
+package org.eclipse.epf.web.search.utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+
+/**
+* A wrapper over the XSLT processor bundled with the JRE.
+*
+* @author Kelvin Low
+* @since 7.0
+*/
+public class XSLTProcessor {
+
+ // If true, cache the compiled the XSL transformer with the compiled XSL
+ // templates.
+ private static boolean cacheXSL = true;
+
+ private static Map cache = new HashMap();
+
+ /**
+ * Default private constructor to prevent this class from being
+ * instantiated.
+ */
+ private XSLTProcessor() {
+ }
+
+ public static Map getCache()
+ {
+ return cache;
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL source, XML source, target
+ * output and encoding.
+ *
+ * @param xslSource
+ * The XSL source.
+ * @param xmlSource
+ * The XML source.
+ * @param output
+ * The output target.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(Source xslSource, Source xmlSource,
+ Writer output, Properties params, String encoding) throws Exception {
+ if (xslSource != null && xmlSource != null) {
+ Transformer transformer = null;
+ String xslSystemId = xslSource.getSystemId();
+ if (cacheXSL && xslSystemId != null) {
+ synchronized (cache) {
+ transformer = (Transformer) cache.get(xslSystemId);
+ if (transformer == null) {
+ TransformerFactory factory = TransformerFactory
+ .newInstance();
+ transformer = factory.newTransformer(xslSource);
+ cache.put(xslSystemId, transformer);
+ }
+ }
+ } else {
+ TransformerFactory factory = TransformerFactory.newInstance();
+ transformer = factory.newTransformer(xslSource);
+ }
+ if (params != null && params.size() > 0) {
+ for (Iterator i = params.keySet().iterator(); i.hasNext();) {
+ String paramName = (String) i.next();
+ String paramValue = params.getProperty(paramName);
+ transformer.setParameter(paramName, paramValue);
+ }
+ }
+ if (encoding != null && encoding.length() > 0) {
+ transformer.setOutputProperty("encoding", encoding); //$NON-NLS-1$
+ } else {
+ transformer.setOutputProperty("encoding", "utf-8"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ transformer.transform(xmlSource, new StreamResult(output));
+ }
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL source, XML source, target
+ * output and encoding.
+ *
+ * @param xslSource
+ * The XSL source.
+ * @param xmlSource
+ * The XML source.
+ * @param output
+ * The output target.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(Source xslSource, Source xmlSource,
+ Writer output, String encoding) throws Exception {
+ transform(xslSource, xmlSource, output, null, encoding);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML source,
+ * target output and encoding.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML source.
+ * @param output
+ * The output target.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(String xslUri, Source xmlSource,
+ Writer output, Properties params, String encoding) throws Exception {
+ InputStream xslInput = getXslInputStream(xslUri);
+ if (xslInput != null) {
+ StreamSource xslSource = new StreamSource(xslInput);
+ xslSource.setSystemId(new File(xslUri));
+ transform(xslSource, xmlSource, output, params, encoding);
+ try {
+ xslInput.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML source,
+ * target output and encoding.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML source.
+ * @param output
+ * The output target.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(String xslUri, Source xmlSource,
+ Writer output, String encoding) throws Exception {
+ transform(xslUri, xmlSource, output, null, encoding);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string,
+ * target output and encoding.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param output
+ * The output target.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(String xslUri, String xmlStr, Writer output,
+ Properties params, String encoding) throws Exception {
+ InputStream xslInput = null;
+ if (cacheXSL && xslUri != null) {
+ synchronized (cache) {
+ xslInput = (InputStream) cache.get(xslUri);
+ if (xslInput == null) {
+ xslInput = getXslInputStream(xslUri);
+ cache.put(xslUri, xslInput);
+ }
+ }
+ } else {
+ xslInput = getXslInputStream(xslUri);
+ }
+ if (xslInput != null) {
+ StreamSource xslSource = new StreamSource(xslInput);
+ xslSource.setSystemId(new File(xslUri));
+
+ byte[] xml = xmlStr.getBytes("utf-8"); //$NON-NLS-1$
+ ByteArrayInputStream xmlInput = new ByteArrayInputStream(xml);
+ StreamSource xmlSource = new StreamSource(xmlInput);
+
+ transform(xslSource, xmlSource, output, params, encoding);
+
+ try {
+ xslInput.close();
+ } catch (FileNotFoundException fne) {
+ fne.printStackTrace();
+ } catch (Exception e) {
+ e.printStackTrace();
+ //throw new Exception(e);
+ }
+ }
+ else
+ throw new FileNotFoundException(xslUri);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string,
+ * target output and encoding.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param output
+ * The output target.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(String xslUri, String xmlStr, Writer output,
+ String encoding) throws Exception {
+ transform(xslUri, xmlStr, output, null, encoding);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string,
+ * target output and encoding.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param file
+ * The output file.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(String xslUri, String xmlStr, File file,
+ Properties params, String encoding) throws Exception {
+ FileWriter output = new FileWriter(file);
+ if (output != null) {
+ transform(xslUri, xmlStr, output, params, encoding);
+ try {
+ output.close();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string,
+ * target output and encoding.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param file
+ * The output file.
+ * @param encoding
+ * The target encoding.
+ */
+ public static void transform(String xslUri, String xmlStr, File file,
+ String encoding) throws Exception {
+ transform(xslUri, xmlStr, file, null, encoding);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML source
+ * and target output.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML source.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param output
+ * The output target.
+ */
+ public static void transform(String xslUri, Source xmlSource,
+ Properties params, Writer output) throws Exception {
+ transform(xslUri, xmlSource, output, params, null);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML source
+ * and target output.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML source.
+ * @param output
+ * The output target.
+ */
+ public static void transform(String xslUri, Source xmlSource, Writer output)
+ throws Exception {
+ transform(xslUri, xmlSource, output, null, null);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string
+ * and target output.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param output
+ * The output target.
+ */
+ public static void transform(String xslUri, String xmlStr,
+ Properties params, Writer output) throws Exception {
+ transform(xslUri, xmlStr, output, params, null);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string
+ * and target output.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param output
+ * The output target.
+ */
+ public static void transform(String xslUri, String xmlStr, Writer output)
+ throws Exception {
+ transform(xslUri, xmlStr, output, null, null);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string
+ * and target output file.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param params
+ * The parameters for the XSL transformation.
+ * @param output
+ * The output target.
+ */
+ public static void transform(String xslUri, String xmlStr,
+ Properties params, File file) throws Exception {
+ transform(xslUri, xmlStr, file, params, null);
+ }
+
+ /**
+ * Executes the XSL transformation given the XSL stylesheet URI, XML string
+ * and target output file.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ * @param xmlStr
+ * The XML string.
+ * @param output
+ * The output target.
+ */
+ public static void transform(String xslUri, String xmlStr, File file)
+ throws Exception {
+ transform(xslUri, xmlStr, file, null, null);
+ }
+
+ /**
+ * Returns the XSL input stream given the XSL stylesheet URI.
+ *
+ * @param xslURI
+ * The XSL stylesheet URI.
+ */
+ private static InputStream getXslInputStream(String xslUri) {
+ InputStream xslInput = null;
+ try {
+ xslInput = (xslUri.startsWith("http")) ? XSLTProcessor.class.getClassLoader()
+ .getResourceAsStream(xslUri) : new FileInputStream(UNCUtil.convertFilename(xslUri));
+ } catch (Exception e) {
+ //e.printStackTrace();
+ if (xslInput == null) {
+ xslInput = XSLTProcessor.class.getClassLoader()
+ .getResourceAsStream(xslUri);
+ }
+ }
+ return xslInput;
+ }
+}
\ No newline at end of file