PageRenderTime 51ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/genesis/org.dftproject.pgv.core/src/org/dftproject/pgv/core/racp/PGVGedcom.java

http://dftproject.googlecode.com/
Java | 345 lines | 252 code | 56 blank | 37 comment | 79 complexity | 1fb4108aff66d1110b5f83a3c7e98261 MD5 | raw file
  1. package org.dftproject.pgv.core.racp;
  2. import java.io.StringReader;
  3. import java.io.UnsupportedEncodingException;
  4. import java.net.URLEncoder;
  5. import java.text.SimpleDateFormat;
  6. import java.util.Arrays;
  7. import java.util.Calendar;
  8. import java.util.Collections;
  9. import java.util.Date;
  10. import java.util.HashSet;
  11. import java.util.LinkedList;
  12. import java.util.List;
  13. import java.util.Set;
  14. import java.util.regex.Matcher;
  15. import java.util.regex.Pattern;
  16. import org.apache.commons.logging.Log;
  17. import org.apache.commons.logging.LogFactory;
  18. import org.dftproject.gedcom.core.AbstractGedcom;
  19. import org.dftproject.gedcom.core.GedcomPerson;
  20. import org.dftproject.gedcom.core.GedcomReader;
  21. import org.dftproject.gedcom.core.IGedcom;
  22. import org.dftproject.gedcom.core.Line;
  23. import org.dftproject.genesis.core.http.HttpManager;
  24. import org.dftproject.genesis.core.persistence.IMemento;
  25. import org.dftproject.genesis.data.genealogy.GenealogyConstants;
  26. import org.dftproject.genesis.data.genealogy.ISource;
  27. import org.dftproject.genesis.data.genealogy.impl.SourceImpl;
  28. import org.dftproject.genesis.data.impl.AttributeImpl;
  29. import org.dftproject.pgv.core.cache.CacheManager;
  30. import org.dftproject.pgv.core.racp.factories.PGVGedcomFactory;
  31. public class PGVGedcom extends AbstractGedcom implements IGedcom {
  32. private static final Log log = LogFactory.getLog(PGVGedcom.class);
  33. private final static Pattern tabbedLinePattern = Pattern.compile("^([^\\t]*)\\t([^\\t]*)$");
  34. private final Session session;
  35. private final String gedcomId;
  36. private String title;
  37. public PGVGedcom(Session session, String gedcomId) {
  38. this(session, gedcomId, null);
  39. }
  40. public PGVGedcom(Session session, String gedcomId, String title) {
  41. this.session = session;
  42. this.gedcomId = gedcomId;
  43. this.title = title;
  44. }
  45. public String getUrl() {
  46. return session.getUrl();
  47. }
  48. public Session getSession() {
  49. return session;
  50. }
  51. public String getGedcomId() {
  52. return gedcomId;
  53. }
  54. public String getTitle() {
  55. return title;
  56. }
  57. protected void initTitle() {
  58. String response = HttpManager.getDefault().getWebPage(session.getUrl() + "client.php?action=listgedcoms&" + session.getSessionComponent());
  59. if (response != null) {
  60. String[] lines = response.split("\n");
  61. if (lines.length > 1 && "SUCCESS".equals(lines[0]) && !lines[1].startsWith("<")) {
  62. for (String line : lines) {
  63. Matcher matcher = tabbedLinePattern.matcher(line);
  64. if (matcher.matches() && gedcomId.equals(matcher.group(1))) {
  65. title = matcher.group(2);
  66. }
  67. }
  68. }
  69. }
  70. }
  71. public String getGedcomUrl() {
  72. try {
  73. return getUrl() + "index.php?ged=" + URLEncoder.encode(getGedcomId(), "UTF-8");
  74. } catch (UnsupportedEncodingException e) {
  75. return null;
  76. }
  77. }
  78. @Override
  79. public GedcomPerson getPerson(String id) {
  80. Line record = getRecord(id);
  81. if (record != null && "INDI".equals(record.getTag()))
  82. return new PGVPerson(this, id, record);
  83. return null;
  84. }
  85. public String getPersonUrl(String id) {
  86. try {
  87. return getUrl() + "individual.php?pid=" + id + "&ged=" + URLEncoder.encode(getGedcomId(), "UTF-8");
  88. } catch (UnsupportedEncodingException e) {
  89. return null;
  90. }
  91. }
  92. /**
  93. * Returns the record associated with <code>id</code>.
  94. * @return the record
  95. */
  96. public Line getRecord(String id) {
  97. Line[] lines = getRecords(new String[] { id });
  98. if (lines.length > 0) {
  99. if (log.isDebugEnabled())
  100. log.debug(lines[0].toString(true));
  101. return lines[0];
  102. }
  103. log.error("Failed to get record for " + id);
  104. return null;
  105. }
  106. /**
  107. * Returns the records associated with the <code>ids</code>.
  108. * @param ids an array of record ids
  109. * @return an array of records
  110. */
  111. public Line[] getRecords(String[] ids) {
  112. if (!session.isValid() && !session.connect())
  113. return new Line[0];
  114. List<Line> lines = new LinkedList<Line>();
  115. // First try to get the record from the cache
  116. CacheManager cacheManager = CacheManager.getDefault();
  117. Date today = getToday();
  118. Set<String> xrefs = new HashSet<String>(Arrays.asList(ids));
  119. for (String xref : ids) {
  120. // The cache must have a retrieval date for a record
  121. Date retrievalDate = cacheManager.getRetrievalDate(getUrl(), gedcomId, xref);
  122. if (retrievalDate == null)
  123. continue;
  124. // The retrieval date must be on or after today
  125. if (!retrievalDate.after(today) && !retrievalDate.equals(today)) {
  126. // If not, we must have request a list of changes today
  127. Date lastGetChanges = cacheManager.getLastGetChanges(getUrl(), gedcomId);
  128. if (lastGetChanges != null && !lastGetChanges.after(today) && !lastGetChanges.equals(today)) {
  129. // If not, request the list of changes and invalidate old
  130. // records
  131. Set<String> changedXrefs = getChanges(lastGetChanges, session.getSessionComponent());
  132. cacheManager.invalidateRecords(getUrl(), gedcomId, today, changedXrefs);
  133. // This record must not have changed since the retrieval
  134. // date
  135. if (changedXrefs.contains(xref)) {
  136. log.info(xref + " has changed since " + new SimpleDateFormat("d MMM yyyy").format(retrievalDate));
  137. continue;
  138. }
  139. }
  140. }
  141. // Get the record from the cache
  142. String record = cacheManager.getRecord(getUrl(), gedcomId, xref);
  143. if (record != null) {
  144. xrefs.remove(xref);
  145. try {
  146. GedcomReader reader = new GedcomReader();
  147. lines.addAll(reader.read(new StringReader(record)));
  148. } catch (Exception e) {
  149. e.printStackTrace();
  150. }
  151. }
  152. }
  153. // Request all cache misses
  154. // TODO Batch record requests with one RACP call and split the results
  155. for (String xref : xrefs) {
  156. Date retrieved = new Date();
  157. String data = getRecords(new String[] { xref }, session.getSessionComponent());
  158. if (data != null) {
  159. cacheManager.putRecord(getUrl(), gedcomId, xref, data, retrieved);
  160. try {
  161. GedcomReader reader = new GedcomReader();
  162. lines.addAll(reader.read(new StringReader(data)));
  163. } catch (Exception e) {
  164. e.printStackTrace();
  165. }
  166. }
  167. }
  168. return lines.toArray(new Line[0]);
  169. }
  170. /**
  171. * Returns a {@link Date} representing the beginning of today.
  172. * @return a date
  173. */
  174. protected Date getToday() {
  175. Calendar today = Calendar.getInstance();
  176. today.set(Calendar.HOUR_OF_DAY, 0);
  177. today.set(Calendar.MINUTE, 0);
  178. today.set(Calendar.SECOND, 0);
  179. today.set(Calendar.MILLISECOND, 0);
  180. return today.getTime();
  181. }
  182. /**
  183. * Returns the data for the requested records.
  184. * @param xrefs an array of xrefs
  185. * @param sessionComponent the session component
  186. * @return the data for the requested records, or null on failure
  187. */
  188. protected String getRecords(String[] xrefs, String sessionComponent) {
  189. if (xrefs == null || xrefs.length == 0 || sessionComponent == null)
  190. return null;
  191. StringBuilder xrefParameter = new StringBuilder();
  192. for (String xref : xrefs)
  193. xrefParameter.append(xref);
  194. String contents= null;
  195. try {
  196. contents = HttpManager.getDefault().getWebPage(getUrl() + "client.php?action=get&GEDCOM=" + URLEncoder.encode(gedcomId, "UTF-8") + "&xref=" + xrefParameter + "&" + sessionComponent);
  197. } catch (UnsupportedEncodingException e) {
  198. log.error("Failed to encode HTTP query parameter as UTF-8", e);
  199. }
  200. if (contents == null)
  201. return null;
  202. String[] lines = contents.split("\n");
  203. if (lines.length < 2)
  204. return null;
  205. if ("SUCCESS".equals(lines[0]) && !lines[1].startsWith("<")) {
  206. StringBuilder data = new StringBuilder();
  207. for (int i = 1; i < lines.length; i++) {
  208. data.append(lines[i]);
  209. if (i < lines.length - 1)
  210. data.append("\n");
  211. }
  212. return data.toString();
  213. }
  214. return null;
  215. }
  216. /**
  217. * Returns a set of xrefs for records that have changed since
  218. * <code>date</code>.
  219. * @param date a date
  220. * @param sessionComponent the session component
  221. * @return a set of xrefs for records that have changed
  222. */
  223. protected Set<String> getChanges(Date date, String sessionComponent) {
  224. if (date == null || sessionComponent == null)
  225. return Collections.emptySet();
  226. String contents = HttpManager.getDefault().getWebPage(getUrl() + "client.php?action=getchanges&GEDCOM=" + gedcomId + "&date=" + date + "&" + sessionComponent);
  227. if (contents == null)
  228. return Collections.emptySet();
  229. String[] lines = contents.split("\n");
  230. if (lines.length < 2)
  231. return Collections.emptySet();
  232. if ("SUCCESS".equals(lines[0]) && !lines[1].startsWith("<")) {
  233. Set<String> xrefs = new HashSet<String>();
  234. for (String line : lines) {
  235. if (!"".equals(line.trim()))
  236. xrefs.add(line);
  237. }
  238. return xrefs;
  239. }
  240. return Collections.emptySet();
  241. }
  242. @Override
  243. public int hashCode() {
  244. final int prime = 31;
  245. int result = 1;
  246. result = prime * result + ((gedcomId == null) ? 0 : gedcomId.hashCode());
  247. result = prime * result + ((session == null) ? 0 : session.hashCode());
  248. return result;
  249. }
  250. @Override
  251. public boolean equals(Object obj) {
  252. if (this == obj)
  253. return true;
  254. if (obj == null)
  255. return false;
  256. if (getClass() != obj.getClass())
  257. return false;
  258. final PGVGedcom other = (PGVGedcom) obj;
  259. if (gedcomId == null) {
  260. if (other.gedcomId != null)
  261. return false;
  262. } else if (!gedcomId.equals(other.gedcomId))
  263. return false;
  264. if (session == null) {
  265. if (other.session != null)
  266. return false;
  267. } else if (!session.equals(other.session))
  268. return false;
  269. return true;
  270. }
  271. public ISource asSource(String id) {
  272. SourceImpl source = new SourceImpl();
  273. source.addAttribute(new AttributeImpl(GenealogyConstants.type, "org.dftproject.pgv.source"));
  274. if (title == null)
  275. initTitle();
  276. if (title != null)
  277. source.addAttribute(new AttributeImpl(GenealogyConstants.title, title));
  278. source.addAttribute(new AttributeImpl(GenealogyConstants.collection, this));
  279. source.addAttribute(new AttributeImpl("id", id));
  280. return source;
  281. }
  282. public String getFactoryId() {
  283. return PGVGedcomFactory.ID;
  284. }
  285. public void saveState(IMemento memento) {
  286. memento.putString("url", session.getUrl());
  287. memento.putString("gedcomId", gedcomId);
  288. }
  289. }