3.4.3. Reading Resource Files

As our WS implementation is dictionary-based, we need – at some point – to read our terms dictionary, i.e., a file containing a list of terms. As this is an expensive operation we only want to do this once for the whole WS so that any later web method calls can reuse the terms dictionary and therewith be faster. In our tutorial implementation we will do this file reading in an extra initialization method which is only called if the initialization has not been done before, i.e., only once. This method will then read the terms dictionary and use it to create a new instance of an OpenNLP DictionaryNameFinder (package opennlp.tools.namefind); the latter will be used to find terms, then. Here is the new initialize method and a new field for the created term finder:

/** the finder to use for identifying terms in sentences */
private TokenNameFinder termFinder = null;

/**
 * Initializes this WS implementation, if necessary.
 * 
 * @throws InternalServiceFault
 *             in case there is any internal problem from which the WS
 *             cannot recover
 */
private synchronized void initialize() throws InternalServiceFault {
	if (this.termFinder != null)
		return;
	this.termFinder = new DictionaryNameFinder(readTermDictionary());
}
As you can see, the actual reading of the term dictionary is performed in the new readTermDictionary method which returns a Dictionary (package opennlp.tools.dictionary); we still need to develop this method, though.

Reading a file in Java is pretty straightforward – as long as you know where to find that file, i.e., as long as you have the complete path to the file. Unfortunately, reading a file from a WS poses just this problem: we may know the relative path to the file from the context root of the WS but usually we don’t know where this context root lies in the file system of the application server that has deployed our WS. The solution to this problem is to let the application server give us this location at deployment time. This is done using resource injection with the following lines of code:

@Resource
private WebServiceContext wsContext = null;
At deployment time the application server fills the wsContext variable with the correct context for our WS. This context can then be used in our readTermDictionary method as follows:
/** path to the terms dictionary file */
private static final String TERMS_DICT_FILE_PATH = "/res/terms.list";

/**
 * Reads the terms dictionary which is specified by
 * {@link #TERMS_DICT_FILE_PATH} and returns it. The file has to contain one
 * term per line where the tokens of each term are separated by whitespaces.
 * 
 * @return the read terms dictionary
 * @throws InternalServiceFault
 *             in case there is some IO problem from which the WS cannot
 *             recover
 */
private Dictionary readTermDictionary() throws InternalServiceFault {
	try {
		return Dictionary
				.parseOneEntryPerLine(new InputStreamReader(WebServiceTools
						.getServletContext(this.wsContext)
						.getResourceAsStream(TERMS_DICT_FILE_PATH), "UTF-8"));
	} catch (UnsupportedEncodingException e) {
		// should never happen
		throw new InternalServiceFault(
				"Could not read the term dictionary.", e.getMessage(), e);
	} catch (IOException e) {
		throw new InternalServiceFault(
				"Could not read the term dictionary.", e.getMessage(), e);
	}
}
Via the WS context we can retrieve the servlet context of our web application with which we can read resources then. As you can see, in the above example we are using the getServletContext method from the QALL-ME Framework’s WebServiceTools (package net.sf.qallme) for convenience to get from the WS context to the servlet context.

Therewith the initialization of our simple WS implementation is done.