001 package crisp.wbwiki.server;
002
003 import javax.servlet.ServletException;
004
005 import org.springframework.context.ApplicationContext;
006 import org.springframework.context.support.FileSystemXmlApplicationContext;
007
008 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
009
010 import crisp.wbwiki.client.Page;
011 import crisp.wbwiki.client.WikiService;
012
013
014 /**
015 * Servlet that receives http requests from Whiteboard Wiki via AJAX.
016 * GWT handles the HTTP requests (in superclass RemoteServiceServlet)
017 * and translates them into simple RPC method calls on WikiServiceImpl. <p>
018 *
019 * Persistence logic is delegated to a WikiDb. This servlet requires a spring application context,
020 * which it uses to look up the WikiDb instance.
021 * Usually this means you should have a /WEB-INF/applicationContext.xml.
022 * For details see:
023 * <ul>
024 * <li>http://www.springframework.org/docs/api/org/springframework/web/context/support/WebApplicationContextUtils.html</li>
025 * <li>http://www.springframework.org/docs/api/org/springframework/web/context/ContextLoader.html</li>
026 * </ul>
027 *
028 * @author Henrik Kniberg
029 */
030 public class WikiServiceImpl extends RemoteServiceServlet implements WikiService {
031 private static final long serialVersionUID = 1L;
032
033 private static final String SPRING_CONTEXT_PATH = "classpath:/wbWikiContext.xml";
034 private WikiDb wikiDb;
035
036
037 public WikiServiceImpl() {
038 super();
039 }
040
041 public WikiServiceImpl(WikiDb wikiDb) {
042 super();
043 setWikiDb(wikiDb);
044 }
045
046 @Override
047 public void init() throws ServletException {
048 super.init();
049
050 //Load spring context
051 ApplicationContext springContext;
052 springContext = new FileSystemXmlApplicationContext(SPRING_CONTEXT_PATH);
053
054 //Get wikiDb bean from context
055 setWikiDb((WikiDb) springContext.getBean("wikiDb", WikiDb.class));
056 }
057
058 protected WikiDb getWikiDb() {
059 return wikiDb;
060 }
061
062 protected void setWikiDb(WikiDb wikiDb) {
063 this.wikiDb = wikiDb;
064 }
065
066 public Page synchronize(Integer lastVersionLoadedByClient, String modifiedContentInClient) {
067 if (modifiedContentInClient != null) {
068 //Aha, new content from the client!
069 if (lastVersionLoadedByClient == null) {
070 throw new IllegalArgumentException("lastVersionLoadedByClient may only be null if modifiedContentInClient is null!");
071 }
072
073 int updatedVersion = wikiDb.savePage(modifiedContentInClient);
074 if (updatedVersion == lastVersionLoadedByClient + 1) {
075 //Ok, no concurrent edits have occurred.
076 //No need to return anything to the client.
077 return null;
078 } else {
079 //Oops, concurrent edits have occurred.
080 //Send the client an updated state.
081 return new Page(updatedVersion, modifiedContentInClient);
082 }
083 } else {
084 //OK, no new content from the client.
085 //Check if there is new content in the DB.
086 synchronized(wikiDb) {
087 int currentVersion = wikiDb.getCurrentVersion();
088 if (lastVersionLoadedByClient == null || currentVersion != lastVersionLoadedByClient) {
089 //Yup, there is new content.
090 //Send the client an updated page.
091 return wikiDb.loadPage();
092 } else {
093 //Nope, no new content.
094 //No need to send anything back to the client.
095 return null;
096 }
097 }
098 }
099 }
100
101 }