Revision 561
Added by berkley about 24 years ago
src/edu/ucsb/nceas/metacat/MetacatReplication.java | ||
---|---|---|
24 | 24 |
import oracle.xml.parser.v2.*; |
25 | 25 |
import org.xml.sax.*; |
26 | 26 |
|
27 |
public class MetacatReplication extends HttpServlet |
|
27 |
public class MetacatReplication extends HttpServlet implements Runnable
|
|
28 | 28 |
{ |
29 | 29 |
private String deltaT; |
30 | 30 |
Timer replicationDaemon; |
31 |
MetaCatUtil util = new MetaCatUtil(); |
|
31 |
private static MetaCatUtil util = new MetaCatUtil(); |
|
32 |
private Vector fileLocks = new Vector(); |
|
33 |
private Thread lockThread = null; |
|
32 | 34 |
|
33 | 35 |
/** |
34 | 36 |
* Initialize the servlet by creating appropriate database connections |
... | ... | |
126 | 128 |
//handleGetDocumentAction(). |
127 | 129 |
handleGetDocumentRequest(out, params, response); |
128 | 130 |
} |
131 |
else if(((String[])params.get("action"))[0].equals("getlock")) |
|
132 |
{ |
|
133 |
handleGetLockRequest(out, params, response); |
|
134 |
} |
|
135 |
else if(((String[])params.get("action"))[0].equals("getdocumentinfo")) |
|
136 |
{ |
|
137 |
handleGetDocumentInfoRequest(out, params, response); |
|
138 |
} |
|
129 | 139 |
} |
130 | 140 |
} |
131 | 141 |
|
142 |
/** |
|
143 |
* Grants or denies a lock to a requesting host. |
|
144 |
* The servlet parameters of interrest are: |
|
145 |
* docid: the docid of the file the lock is being requested for |
|
146 |
* currentdate: the timestamp of the document on the remote server |
|
147 |
* |
|
148 |
*/ |
|
149 |
private void handleGetLockRequest(PrintWriter out, Hashtable params, |
|
150 |
HttpServletResponse response) |
|
151 |
{ |
|
152 |
java.util.Date remoteDate = new java.util.Date(); |
|
153 |
java.util.Date localDate = new java.util.Date(); |
|
154 |
try |
|
155 |
{ |
|
156 |
Connection conn = util.openDBConnection(); |
|
157 |
String docid = ((String[])params.get("docid"))[0]; |
|
158 |
String remoteDateStr = ((String[])params.get("updatedate"))[0]; |
|
159 |
DocumentImpl requestDoc = new DocumentImpl(conn, docid); |
|
160 |
|
|
161 |
String localDateStr = requestDoc.getUpdateDate(); |
|
162 |
SimpleDateFormat formatter = new SimpleDateFormat ("yy-MM-dd HH:mm:ss"); |
|
163 |
ParsePosition pos = new ParsePosition(0); |
|
164 |
remoteDate = formatter.parse(remoteDateStr, pos); |
|
165 |
localDate = formatter.parse(localDateStr, pos); |
|
166 |
if(remoteDate.compareTo(localDate) >= 0) |
|
167 |
{ |
|
168 |
if(!fileLocks.contains(docid)) |
|
169 |
{ //grant the lock |
|
170 |
fileLocks.add(0, docid); //insert at the beginning of the queue Vector |
|
171 |
//send a message back to the the remote host authorizing the insert |
|
172 |
out.println("<lockgranted><docid>" +docid+ "</docid></lockgranted>"); |
|
173 |
lockThread = new Thread(this); |
|
174 |
lockThread.setPriority(Thread.MIN_PRIORITY); |
|
175 |
lockThread.start(); |
|
176 |
} |
|
177 |
else |
|
178 |
{ //deny the lock |
|
179 |
out.println("<filelocked><docid>" + docid + "</docid></filelocked>"); |
|
180 |
} |
|
181 |
} |
|
182 |
else |
|
183 |
{//deny the lock. |
|
184 |
out.println("<outdatedfile><docid>" + docid + "</docid></filelocked>"); |
|
185 |
} |
|
186 |
conn.close(); |
|
187 |
} |
|
188 |
catch(Exception e) |
|
189 |
{ |
|
190 |
System.out.println("error requesting file lock: " + e.getMessage()); |
|
191 |
} |
|
192 |
} |
|
193 |
|
|
194 |
/** |
|
195 |
* Sends all of the xml_documents information encoded in xml to a requestor |
|
196 |
*/ |
|
197 |
private void handleGetDocumentInfoRequest(PrintWriter out, Hashtable params, |
|
198 |
HttpServletResponse response) |
|
199 |
{ |
|
200 |
String docid = ((String[])(params.get("docid")))[0]; |
|
201 |
StringBuffer sb = new StringBuffer(); |
|
202 |
try |
|
203 |
{ |
|
204 |
Connection conn = util.openDBConnection(); |
|
205 |
DocumentImpl doc = new DocumentImpl(conn, docid); |
|
206 |
sb.append("<documentinfo><docid>").append(docid); |
|
207 |
sb.append("</docid><docname>").append(doc.getDocname()); |
|
208 |
sb.append("</docname><doctype>").append(doc.getDoctype()); |
|
209 |
sb.append("</doctype><doctitle>").append(doc.getDocTitle()); |
|
210 |
sb.append("</doctitle><user_owner>").append(doc.getUserowner()); |
|
211 |
sb.append("</user_owner><user_updated>").append(doc.getUserupdated()); |
|
212 |
sb.append("</user_updated><public_access>").append(doc.getPublicaccess()); |
|
213 |
sb.append("</public_access></documentinfo>"); |
|
214 |
response.setContentType("text/xml"); |
|
215 |
out.println(sb.toString()); |
|
216 |
conn.close(); |
|
217 |
} |
|
218 |
catch (Exception e) |
|
219 |
{ |
|
220 |
System.out.println("error in metacatReplication.handlegetdocumentinforequest: " + |
|
221 |
e.getMessage()); |
|
222 |
} |
|
223 |
|
|
224 |
} |
|
225 |
|
|
226 |
/** |
|
227 |
* Sends a document to a remote host |
|
228 |
*/ |
|
132 | 229 |
private void handleGetDocumentRequest(PrintWriter out, Hashtable params, |
133 |
HttpServletResponse response) |
|
230 |
HttpServletResponse response)
|
|
134 | 231 |
{ |
135 | 232 |
try |
136 | 233 |
{ |
... | ... | |
176 | 273 |
java.util.Date update = new java.util.Date(); |
177 | 274 |
ParsePosition pos = new ParsePosition(0); |
178 | 275 |
update = formatter.parse(updateStr, pos); |
179 |
//update = new java.util.Date(update.getTime() - 10000); |
|
180 | 276 |
String dateString = formatter.format(update); |
181 | 277 |
sql.append("select docid, date_updated, server_location from "); |
182 | 278 |
sql.append("xml_documents where date_updated > "); |
183 |
sql.append("to_date('").append(dateString).append("','YY-MM-DD HH24:MI:SS')"); |
|
279 |
sql.append("to_date('").append(dateString); |
|
280 |
sql.append("','YY-MM-DD HH24:MI:SS')"); |
|
184 | 281 |
//System.out.println("sql: " + sql.toString()); |
185 | 282 |
|
186 | 283 |
//get any recently deleted documents |
187 | 284 |
StringBuffer delsql = new StringBuffer(); |
188 |
delsql.append("select docid, date_created, server_location from ");
|
|
285 |
delsql.append("select docid, date_updated, server_location from ");
|
|
189 | 286 |
delsql.append("xml_revisions where docid not in (select docid from "); |
190 |
delsql.append("xml_documents) and date_created > to_date('");
|
|
287 |
delsql.append("xml_documents) and date_updated > to_date('");
|
|
191 | 288 |
delsql.append(dateString).append("','YY-MM-DD HH24:MI:SS')"); |
192 | 289 |
|
193 | 290 |
try |
... | ... | |
247 | 344 |
System.out.println("Exception in metacatReplication: " + e.getMessage()); |
248 | 345 |
} |
249 | 346 |
} |
347 |
|
|
348 |
/** |
|
349 |
* This method is what is run when a seperate thread is broken off to handle |
|
350 |
* inserting a document from a remote replicated server. |
|
351 |
*/ |
|
352 |
public void run() |
|
353 |
{ |
|
354 |
try |
|
355 |
{ |
|
356 |
Thread.sleep(30000); //the lock will expire in 30 seconds |
|
357 |
fileLocks.remove(fileLocks.size() - 1); |
|
358 |
//the vector is treated as a FIFO queue. If there are more than one lock |
|
359 |
//in the vector, the first one inserted will be removed. |
|
360 |
} |
|
361 |
catch(Exception e) |
|
362 |
{ |
|
363 |
System.out.println("error in file lock thread: " + e.getMessage()); |
|
364 |
} |
|
365 |
} |
|
366 |
|
|
367 |
/** |
|
368 |
* Returns the name of a server given a serverCode |
|
369 |
* @param serverCode the serverid of the server |
|
370 |
* @return the servername or null if the specified serverCode does not |
|
371 |
* exist. |
|
372 |
*/ |
|
373 |
public static String getServer(int serverCode) |
|
374 |
{ |
|
375 |
try |
|
376 |
{ |
|
377 |
Connection conn = util.openDBConnection(); |
|
378 |
PreparedStatement pstmt = conn.prepareStatement("select server from " + |
|
379 |
"xml_replication where serverid = " + |
|
380 |
serverCode); |
|
381 |
pstmt.execute(); |
|
382 |
ResultSet rs = pstmt.getResultSet(); |
|
383 |
boolean tablehasrows = rs.next(); |
|
384 |
if(tablehasrows) |
|
385 |
{ |
|
386 |
conn.close(); |
|
387 |
return rs.getString(1); |
|
388 |
} |
|
389 |
conn.close(); |
|
390 |
} |
|
391 |
catch(Exception e) |
|
392 |
{ |
|
393 |
System.out.println("Error in MetacatReplication.getServer: " + |
|
394 |
e.getMessage()); |
|
395 |
} |
|
396 |
return null; |
|
397 |
//return null if the server does not exist |
|
398 |
} |
|
250 | 399 |
} |
src/edu/ucsb/nceas/metacat/DocumentImpl.java | ||
---|---|---|
21 | 21 |
import java.io.Reader; |
22 | 22 |
import java.io.StringWriter; |
23 | 23 |
import java.io.Writer; |
24 |
import java.io.InputStreamReader; |
|
24 | 25 |
|
25 | 26 |
import java.util.Iterator; |
26 | 27 |
import java.util.Stack; |
... | ... | |
37 | 38 |
import org.xml.sax.SAXParseException; |
38 | 39 |
import org.xml.sax.helpers.XMLReaderFactory; |
39 | 40 |
|
41 |
import java.net.URL; |
|
42 |
|
|
40 | 43 |
/** |
41 | 44 |
* A class that represents an XML document. It can be created with a simple |
42 | 45 |
* document identifier from a database connection. It also will write an |
... | ... | |
56 | 59 |
private String createdate = null; |
57 | 60 |
private String updatedate = null; |
58 | 61 |
private String system_id = null; |
62 |
private String userowner = null; |
|
63 |
private String userupdated = null; |
|
64 |
private int serverlocation; |
|
65 |
private int publicaccess; |
|
59 | 66 |
private long rootnodeid; |
60 | 67 |
private ElementNode rootNode = null; |
61 | 68 |
private TreeSet nodeRecordList = null; |
... | ... | |
187 | 194 |
public String getDocTitle() { |
188 | 195 |
return doctitle; |
189 | 196 |
} |
197 |
|
|
198 |
public String getUserowner() { |
|
199 |
return userowner; |
|
200 |
} |
|
201 |
|
|
202 |
public String getUserupdated() { |
|
203 |
return userupdated; |
|
204 |
} |
|
205 |
|
|
206 |
public int getServerlocation() { |
|
207 |
return serverlocation; |
|
208 |
} |
|
209 |
|
|
210 |
public int getPublicaccess() { |
|
211 |
return publicaccess; |
|
212 |
} |
|
190 | 213 |
|
191 |
|
|
192 | 214 |
/** |
193 | 215 |
* Print a string representation of the XML document |
194 | 216 |
*/ |
... | ... | |
375 | 397 |
try { |
376 | 398 |
pstmt = |
377 | 399 |
conn.prepareStatement("SELECT docname, doctype, rootnodeid,doctitle, " + |
378 |
"date_created, date_updated " + |
|
400 |
"date_created, date_updated, " + |
|
401 |
"user_owner, user_updated, server_location, " + |
|
402 |
"public_access " + |
|
379 | 403 |
"FROM xml_documents " + |
380 | 404 |
"WHERE docid LIKE ?"); |
381 | 405 |
// Bind the values to the query |
... | ... | |
385 | 409 |
ResultSet rs = pstmt.getResultSet(); |
386 | 410 |
boolean tableHasRows = rs.next(); |
387 | 411 |
if (tableHasRows) { |
388 |
this.docname = rs.getString(1); |
|
389 |
this.doctype = rs.getString(2); |
|
390 |
this.rootnodeid = rs.getLong(3); |
|
391 |
this.doctitle = rs.getString(4); |
|
392 |
this.createdate = rs.getString(5); |
|
393 |
this.updatedate = rs.getString(6); |
|
412 |
this.docname = rs.getString(1); |
|
413 |
this.doctype = rs.getString(2); |
|
414 |
this.rootnodeid = rs.getLong(3); |
|
415 |
this.doctitle = rs.getString(4); |
|
416 |
this.createdate = rs.getString(5); |
|
417 |
this.updatedate = rs.getString(6); |
|
418 |
this.userowner = rs.getString(7); |
|
419 |
this.userupdated = rs.getString(8); |
|
420 |
this.serverlocation = rs.getInt(9); |
|
421 |
this.publicaccess = rs.getInt(10); |
|
394 | 422 |
} |
395 | 423 |
pstmt.close(); |
396 | 424 |
|
... | ... | |
699 | 727 |
String action, String docid, String user, |
700 | 728 |
String group, int serverCode ) |
701 | 729 |
throws Exception { |
702 |
/*
|
|
703 |
if(serverCode != 1) |
|
730 |
System.out.println("outside of if: action: " + action + "servercode: " + serverCode);
|
|
731 |
if(serverCode != 1 && action.equals("UPDATE"))
|
|
704 | 732 |
{ //if this document being written is not a resident of this server then |
705 | 733 |
//we need to try to get a lock from it's resident server. If the |
706 | 734 |
//resident server will not give a lock then we send the user a message |
707 | 735 |
//saying that he/she needs to download a new copy of the file and |
708 | 736 |
//merge the differences manually. |
737 |
System.out.println("in if: action: " + action + "servercode: " + serverCode); |
|
738 |
int istreamInt; |
|
739 |
char istreamChar; |
|
740 |
DocumentImpl newdoc = new DocumentImpl(conn, docid); |
|
741 |
String update = newdoc.getUpdateDate(); |
|
742 |
String server = MetacatReplication.getServer(serverCode); |
|
709 | 743 |
|
744 |
URL u = new URL("http://" + server + "?action=getlock&updatedate=" + update + |
|
745 |
"&docid=" + docid); |
|
746 |
InputStreamReader istream = new InputStreamReader(u.openStream()); |
|
747 |
StringBuffer serverResponse = new StringBuffer(); |
|
748 |
while((istreamInt = istream.read()) != -1) |
|
749 |
{ |
|
750 |
istreamChar = (char)istreamInt; |
|
751 |
serverResponse.append(istreamChar); |
|
752 |
} |
|
710 | 753 |
|
754 |
String serverResStr = serverResponse.toString(); |
|
755 |
String openingtag = serverResStr.substring(0, serverResStr.indexOf(">")); |
|
756 |
System.out.println("openingtag: " + openingtag); |
|
757 |
if(openingtag.equals("<lockgranted>")) |
|
758 |
{//the lock was granted go ahead with the insert |
|
759 |
|
|
760 |
} |
|
761 |
else if(openingtag.equals("<filelocked>")) |
|
762 |
{//the file is currently locked by another user |
|
763 |
//notify our user to wait a few minutes, check out a new copy and try |
|
764 |
//again. |
|
765 |
|
|
766 |
} |
|
767 |
else if(openingtag.equals("<outdatedfile>")) |
|
768 |
{//our file is outdated. notify our user to check out a new copy of the |
|
769 |
//file and merge his version with the new version. |
|
770 |
|
|
771 |
} |
|
711 | 772 |
} |
712 |
*/ |
|
773 |
|
|
713 | 774 |
// Determine if the docid is OK for INSERT or UPDATE |
714 | 775 |
AccessionNumber ac = new AccessionNumber(conn); |
715 | 776 |
String newdocid = ac.generate(docid, action); |
src/edu/ucsb/nceas/metacat/ReplMessageHandler.java | ||
---|---|---|
27 | 27 |
import org.xml.sax.helpers.DefaultHandler; |
28 | 28 |
|
29 | 29 |
/** |
30 |
* A database aware Class implementing callback bethods for the SAX parser to
|
|
30 |
* A Class implementing callback bethods for the SAX parser to |
|
31 | 31 |
* call when processing the XML messages from the replication handler |
32 | 32 |
*/ |
33 | 33 |
public class ReplMessageHandler extends DefaultHandler |
src/edu/ucsb/nceas/metacat/ReplicationHandler.java | ||
---|---|---|
29 | 29 |
import org.xml.sax.SAXException; |
30 | 30 |
import org.xml.sax.SAXParseException; |
31 | 31 |
import org.xml.sax.helpers.XMLReaderFactory; |
32 |
import org.xml.sax.helpers.DefaultHandler; |
|
32 | 33 |
|
34 |
|
|
35 |
|
|
33 | 36 |
/** |
34 | 37 |
* This class handles deltaT replication checking. Whenever this TimerTask |
35 | 38 |
* is fired it checks each server in xml_replication for updates and updates |
... | ... | |
186 | 189 |
//work as a param to this method but it doesn'. I don't know why |
187 | 190 |
//but putting a string reader there works but not an |
188 | 191 |
//inputStreamReader. |
192 |
DocInfoHandler dih = new DocInfoHandler(); |
|
193 |
XMLReader docinfoParser = initParser(dih); |
|
194 |
URL docinfoUrl = new URL("http://" + docServer + |
|
195 |
"?action=getdocumentinfo&docid=" + |
|
196 |
docid); |
|
197 |
InputStreamReader isr = new InputStreamReader( |
|
198 |
docinfoUrl.openStream()); |
|
199 |
StringBuffer docInfoBuffer = new StringBuffer(); |
|
200 |
while((istreamInt = isr.read()) != 1) |
|
201 |
{ |
|
202 |
istreamChar = (char)istreamInt; |
|
203 |
docInfoBuffer.append(istreamChar); |
|
204 |
} |
|
205 |
|
|
206 |
docinfoParser.parse(new InputSource(new StringReader( |
|
207 |
docInfoBuffer.toString()))); |
|
208 |
Hashtable docinfoHash = dih.getDocInfo(); |
|
209 |
|
|
189 | 210 |
String newDocid = DocumentImpl.write(conn, |
190 |
new StringReader(serverResponse.toString()) |
|
191 |
/*getDocIstream*/, |
|
192 |
action, |
|
193 |
docid, null, null, serverCode); |
|
211 |
new StringReader(serverResponse.toString()) |
|
212 |
/*getDocIstream*/, |
|
213 |
action, |
|
214 |
docid, (String)docinfoHash.get("user_owner"), |
|
215 |
(String)docinfoHash.get("user_owner"), |
|
216 |
serverCode); |
|
194 | 217 |
System.out.println("newDocid: " + newDocid + " " + action + "ED"); |
195 | 218 |
} |
196 | 219 |
} |
... | ... | |
201 | 224 |
String docid = (String)w.elementAt(0); |
202 | 225 |
|
203 | 226 |
DocumentImpl.delete(conn, docid, null, null); |
227 |
System.out.println("Document " + docid + " deleted."); |
|
204 | 228 |
} |
205 | 229 |
} |
206 | 230 |
|
... | ... | |
267 | 291 |
/** |
268 | 292 |
* Method to initialize the message parser |
269 | 293 |
*/ |
270 |
private static XMLReader initParser(ReplMessageHandler rmh)
|
|
294 |
private static XMLReader initParser(DefaultHandler dh)
|
|
271 | 295 |
throws Exception |
272 | 296 |
{ |
273 | 297 |
XMLReader parser = null; |
274 | 298 |
|
275 | 299 |
try { |
276 |
ContentHandler chandler = rmh;
|
|
300 |
ContentHandler chandler = dh;
|
|
277 | 301 |
|
278 | 302 |
// Get an instance of the parser |
279 | 303 |
MetaCatUtil util = new MetaCatUtil(); |
Also available in: Unified diff
added functionality to allow the replication servlet to assertain and insert user and group info into the local database. started implementation of insert replication handler (it is commented out in this commit)