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 }