|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 3 of 7
Most pedagogical REST examples show CRUDish services (Create, Retrieve, Update, Delete) around simple objects. Although that style certainly works well with REST, it is by no means the only approach that makes sense -- and most of us are tired of CRUD examples, anyway. The following example demonstrates the basics of a Restlet application by wrapping the Jazzy open source spell checker.
REST is about managing information, not invoking arbitrary behavior, so you need to exercise care when considering a behavior-oriented
API like Jazzy. The trick is to treat the RESTful API as an information space for words that do and do not exist within the
dictionaries in use. The problem could be solved in a variety of ways, but this article will define two information spaces.
/dictionary is used to manage words in the dictionary. /spellchecker is used to find suggestions for words similar to misspelled words. Both focus on information by considering the absence or
presence of words in the information spaces.
In a RESTful architecture, this HTTP command could return a definition of a word in the dictionary:
GET http://localhost:8182/dictionary/word
It would probably return the HTTP response code "Not Found" for words that are not in the dictionary. In this information space, it is fine to indicate that words do not exist. Jazzy does not provide definitions for words, so I'll leave returning some content as an exercise for the reader.
This next HTTP command should add a word to the dictionary:
PUT http://localhost:8182/dictionary/word
This example uses PUT because you can figure out what the URI in the /dictionary information space should be beforehand, and issuing multiple PUTs should not make a difference. (PUT is an idempotent request, like GET. Issuing the same command multiple times should not make a difference.) If you want to add definitions, you could pass them
in as bodies to the PUT handler. If you want to accept multiple definitions over time, you may wish to POST those definitions in, because PUT is an overwrite operation.
In the interest of keeping the examples focused, this article pays no special attention to synchronization issues. Do not treat your production code so nonchalantly! Consult a resource such as Java Concurrency in Practice for more information.
The Restlet instances that I'll create need to be bound to the appropriate information spaces, as shown in Listing 3.
package net.bosatsu.restlet.spell;
import com.swabunga.spell.event.SpellChecker;
import com.swabunga.spell.engine.GenericSpellDictionary;
import com.swabunga.spell.engine.SpellDictionary;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.restlet.data.Protocol;
import org.restlet.*;
public class SpellCheckingServer extends Application {
public static String dictionary = "Restlet/dict/english.0";
public static SpellDictionary spellingDict;
public static SpellChecker spellChecker;
public static Restlet spellCheckerRestlet;
public static Restlet dictionaryRestlet;
static {
try {
spellingDict = new GenericSpellDictionary(new File(dictionary));
spellChecker = new SpellChecker(spellingDict);
spellCheckerRestlet = new SpellCheckerRestlet(spellChecker);
dictionaryRestlet = new DictionaryRestlet(spellChecker);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String [] args) throws Exception {
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
SpellCheckingServer spellingService = new SpellCheckingServer();
component.getDefaultHost().attach("", spellingService);
component.start();
}
public Restlet createRoot() {
Router router = new Router(getContext());
router.attach("/spellchecker/{word}", spellCheckerRestlet);
router.attach("/dictionary/{word}", dictionaryRestlet);
return router;
}
}
After it builds up the dictionary instance and the spell checker, the Restlet setup in Listing 3 is slightly more complicated
than in the earlier basic example (but not much!). The SpellCheckingServer is an instance of a Restlet Application. An Application is an organizational class that coordinates deployment of functionally connected Restlet instances. The surrounding Component asks an Application for its root Restlet by calling the createRoot() method. The root Restlet returned indicates who should respond to the external requests. In this example, a class called Router is used to dispatch to the subordinate information spaces. In addition to performing this context binding, it sets up a URL
pattern that allows the "word" portion of the URL to be available as an attribute on the request. This will be leveraged in
the Restlets created in Listings 4 and 5.