PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/spindles-api/src/spindles/api/services/ImportService.java

http://spindles.googlecode.com/
Java | 483 lines | 326 code | 113 blank | 44 comment | 18 complexity | 388950b40fcfce30ddae7a62493e1339 MD5 | raw file
  1. package spindles.api.services;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.util.ArrayList;
  5. import java.util.Collection;
  6. import java.util.Date;
  7. import java.util.List;
  8. import java.util.NoSuchElementException;
  9. import java.util.Scanner;
  10. import java.util.SortedSet;
  11. import java.util.concurrent.ArrayBlockingQueue;
  12. import java.util.concurrent.BlockingQueue;
  13. import org.apache.commons.io.FilenameUtils;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import spindles.api.db.DAO;
  17. import spindles.api.db.DB;
  18. import spindles.api.db.DBGateway;
  19. import spindles.api.db.PersonDAO;
  20. import spindles.api.db.SessionPartDAO;
  21. import spindles.api.db.SleepSessionDAO;
  22. import spindles.api.domain.Audit;
  23. import spindles.api.domain.Epoch;
  24. import spindles.api.domain.Interval;
  25. import spindles.api.domain.Person;
  26. import spindles.api.domain.SessionPart;
  27. import spindles.api.domain.Settings;
  28. import spindles.api.domain.SleepSession;
  29. import spindles.api.domain.ThresholdGroup;
  30. import spindles.api.domain.User;
  31. import spindles.api.domain.VDSpindle;
  32. import spindles.api.util.ApplicationException;
  33. import spindles.api.util.ErrorMessages;
  34. import spindles.api.util.FileUtil;
  35. import spindles.api.util.Processor;
  36. import spindles.api.util.UserException;
  37. import spindles.api.util.Util;
  38. import com.sleepycat.je.Transaction;
  39. public class ImportService {
  40. final Logger log = LoggerFactory.getLogger(ImportService.class);
  41. private File file;
  42. private EEGParser parser;
  43. private PersonDAO personDAO = new PersonDAO();
  44. private SessionPartDAO partDAO = new SessionPartDAO();
  45. private SleepSessionDAO sessionDAO = new SleepSessionDAO();
  46. private DBGateway db = new DBGateway();
  47. private DAO<Epoch> epochDAO = new DAO<Epoch>(Epoch.class, "sessionPartID");
  48. private DAO<Audit> auditDAO = new DAO<Audit>(Audit.class);
  49. private Transaction impTxn;
  50. private ThresholdGroup group;
  51. private Audit audit;
  52. public ImportService(ThresholdGroup group){
  53. setThresholdGroup(group);
  54. }
  55. public ImportService(){};
  56. private void validateFilename(String filename) throws UserException{
  57. if(!FileUtil.validFilename(filename)){
  58. throw new UserException(ErrorMessages.FILENAME_INVALID);
  59. }
  60. }
  61. public void setThresholdGroup(ThresholdGroup group){
  62. this.group = group;
  63. }
  64. public void importSettings(String exportDir){
  65. importThresholdGroups();
  66. Transaction txn = DB.beginTransaction();
  67. try{
  68. DAO<Settings> dao = new DAO<Settings>(Settings.class);
  69. dao.setTransaction(txn);
  70. Settings s = new Settings();
  71. s.setDefaultGroupName(db.getDefaultThresholdGroup().getGroupName());
  72. s.setExportDirectory(exportDir);
  73. s.setShowOnlyRawData(false);
  74. s.setPlotHeight(800);
  75. s.setPlotWidth(1100);
  76. dao.put(s);
  77. dao.commit();
  78. } catch(ApplicationException e){
  79. DB.abort(txn);
  80. throw e;
  81. }
  82. }
  83. public void importThresholdGroups(){
  84. Transaction txn = DB.beginTransaction();
  85. try{
  86. DAO<ThresholdGroup> dao = new DAO<ThresholdGroup>(ThresholdGroup.class);
  87. dao.setTransaction(txn);
  88. List<ThresholdGroup> all = ThresholdGroup.findAll();
  89. for(ThresholdGroup group : all){
  90. try {
  91. db.getThresholdGroup(group.getGroupName());
  92. } catch (NoSuchElementException e) {
  93. dao.put(group);
  94. continue;
  95. }
  96. }
  97. dao.commit();
  98. } catch(ApplicationException e){
  99. DB.abort(txn);
  100. throw e;
  101. }
  102. }
  103. public void importUsers(){
  104. Transaction txn = DB.beginTransaction();
  105. try{
  106. DAO<User> dao = new DAO<User>(User.class);
  107. dao.setTransaction(txn);
  108. try {
  109. db.getUser(User.DEFAULT_USERNAME);
  110. } catch (NoSuchElementException e) {
  111. dao.put(User.getDefaultUser());
  112. }
  113. dao.commit();
  114. } catch(ApplicationException e){
  115. DB.abort(txn);
  116. throw e;
  117. }
  118. }
  119. public void importSpindles(String filename, final long sessionPartID)
  120. throws UserException{
  121. Transaction txn = DB.beginTransaction();
  122. try {
  123. epochDAO.setTransaction(txn);
  124. validateFilename(filename);
  125. file = new File(filename);
  126. FileUtil.readFile(file, new Processor() {
  127. public void process(BufferedReader r) throws Exception {
  128. Collection<Epoch> epochs = epochDAO
  129. .findAllSorted(sessionPartID);
  130. User user = db.getUser(User.DEFAULT_USERNAME);
  131. String line = null;
  132. Interval lastISI = null;
  133. for (Epoch e : epochs) {
  134. line = r.readLine();
  135. while (!Util.isEmpty(line)) {
  136. Scanner scan = new Scanner(line).useDelimiter("\t");
  137. VDSpindle s = new VDSpindle(user,
  138. Util.addSeconds(e.getStart(), scan
  139. .nextDouble()), Util.addSeconds(e
  140. .getStart(), scan.nextDouble()));
  141. e.addSpindle(s);
  142. line = r.readLine();
  143. }
  144. lastISI = e.setISIs(user, lastISI);
  145. epochDAO.put(e);
  146. }
  147. }
  148. });
  149. epochDAO.commit();
  150. } catch (ApplicationException e) {
  151. DB.abort(txn);
  152. throw e;
  153. }
  154. }
  155. public long importSessionPartData(String filename, String channel) throws UserException{
  156. return importSessionPartData(filename, channel, false, false);
  157. }
  158. /**
  159. * Imports a file with EEG data in the BrainQuick format, in the
  160. * Berkeley DB.
  161. * There are 5 cases. Import data for:
  162. * <ol>
  163. * <li>A new person and create a new record for her.</li>
  164. * <li>An existing person and create a new record for her
  165. * (allowDuplicatePerson=true).</li>
  166. * <li>An existing person, but a new sleep session.</li>
  167. * <li>An existing person and sleep session, but a new session part.</li>
  168. * <li>An existing person, sleep session and session part, but assume that
  169. * it is a new session part (allowDuplicateSessionPart=true).
  170. * </ol>
  171. *
  172. * @param filename
  173. * @param allowDuplicatePerson
  174. * @param allowDuplicateSessionPart
  175. * @throws UserException
  176. */
  177. public long importSessionPartData(String filename,
  178. String channel,
  179. boolean allowDuplicatePerson,
  180. boolean allowDuplicateSessionPart) throws UserException{
  181. impTxn = DB.beginTransaction();
  182. log.info("Started import transaction...");
  183. audit = new Audit();
  184. try {
  185. personDAO.setTransaction(impTxn);
  186. partDAO.setTransaction(impTxn);
  187. sessionDAO.setTransaction(impTxn);
  188. epochDAO.setTransaction(impTxn);
  189. auditDAO.setTransaction(impTxn);
  190. validateFilename(filename);
  191. file = new File(filename);
  192. parser = new EEGParser(file, channel);
  193. audit.setFilename(FilenameUtils.getName(filename));
  194. audit.setFileSize((int)file.length()/1024/1024);
  195. audit.setImportStartTime(new Date());
  196. audit.setRecordsCount(FileUtil.getRecordsCount(file));
  197. audit.setSamplingRate(parser.getSamplingRate().value());
  198. // New person
  199. Person p = parsePerson();
  200. if (!personDAO.exists(p)) {
  201. return importNewPersonData(p);
  202. }
  203. // Person is already in the db
  204. Person personInDB = personDAO.find(p.getFirstName(), p
  205. .getLastName());
  206. if (allowDuplicatePerson) {
  207. return importNewPersonData(p);
  208. }
  209. Date sleepStart = parser.getSessionStartDate();
  210. SleepSession sleepInDB = sessionDAO.findSleepSession(sleepStart,
  211. personInDB.getId());
  212. // New sleep session
  213. if (sleepInDB == null) {
  214. return importNewSleepSessionData(new SleepSession(sleepStart,
  215. parser.getSamplingRate(), personInDB.getId()));
  216. }
  217. // Sleep session exists
  218. Date partStart = parser.getPartStartDate();
  219. SessionPart sessionPart = new SessionPart(partStart, parser
  220. .getChannel(), sleepInDB.getId());
  221. if (!partDAO.existsSessionPart(partStart, sessionPart.getChannel(),
  222. sleepInDB.getId())) {
  223. return importNewSessionPartData(sessionPart);
  224. }
  225. // Sleep session part exists
  226. if (allowDuplicateSessionPart) {
  227. return importNewSessionPartData(sessionPart);
  228. }
  229. } catch (ApplicationException e) {
  230. DB.abort(impTxn);
  231. throw e;
  232. }
  233. DB.abort(impTxn);
  234. throw new UserException(ErrorMessages.FILE_IMPORTED);
  235. }
  236. protected long importNewPersonData(Person p) throws UserException{
  237. personDAO.put(p);
  238. SleepSession session = new SleepSession(parser.getSessionStartDate(),
  239. parser.getSamplingRate(), p.getId());
  240. return importNewSleepSessionData(session);
  241. }
  242. protected long importNewSleepSessionData(SleepSession sleep)
  243. throws UserException {
  244. sessionDAO.put(sleep);
  245. SessionPart part = new SessionPart(parser.getPartStartDate(), parser
  246. .getChannel(), sleep.getId());
  247. return importNewSessionPartData(part);
  248. }
  249. private class Producer implements Runnable {
  250. private final BlockingQueue<List<Double>> queue;
  251. private boolean close = false;
  252. public Producer(BlockingQueue<List<Double>> q) {
  253. queue = q;
  254. }
  255. public void run() {
  256. try {
  257. while (!close) {
  258. queue.put(produce());
  259. }
  260. } catch (UserException e){
  261. throw new ApplicationException(e);
  262. } catch (InterruptedException ex) {
  263. throw new ApplicationException(ex);
  264. }
  265. }
  266. public List<Double> produce() throws UserException {
  267. List<Double> data = parser.getNextEpoch();
  268. if(data != null){
  269. return data;
  270. }
  271. close = true;
  272. return new ArrayList<Double>();
  273. }
  274. }
  275. private class Consumer implements Runnable {
  276. private final BlockingQueue<List<Double>> queue;
  277. private final Long id;
  278. private int index = -1;
  279. private Epoch epoch = null;
  280. private Interval softLastISI = null;
  281. private Interval hardLastISI = null;
  282. private Date end;
  283. public Consumer(BlockingQueue<List<Double>> q, Long id) {
  284. queue = q;
  285. this.id = id;
  286. }
  287. public Date getEnd(){
  288. return end;
  289. }
  290. public void run() {
  291. try {
  292. while (true) {
  293. if(!consume(queue.take())){
  294. break;
  295. }
  296. }
  297. } catch (InterruptedException ex) {
  298. throw new ApplicationException(ex);
  299. }
  300. }
  301. public boolean consume(List<Double> samples) {
  302. index++;
  303. if(samples.isEmpty()){
  304. end = epoch.getEnd();
  305. return false;
  306. }
  307. if (index == 0){
  308. epoch = new Epoch(parser.getPartStartDate(), id);
  309. } else{
  310. epoch = new Epoch(new Date(epoch.getEnd().getTime()), id);
  311. }
  312. epoch.setEEGSamples(samples);
  313. epoch.detectAndLoadSpindleIndications(parser.getSamplingRate(), group);
  314. softLastISI = epoch.setISIs(group, true, softLastISI);
  315. hardLastISI = epoch.setISIs(group, false, hardLastISI);
  316. epochDAO.put(epoch);
  317. return true;
  318. }
  319. }
  320. protected long importNewSessionPartData(SessionPart part) throws UserException{
  321. try {
  322. partDAO.put(part);
  323. BlockingQueue<List<Double>> q = new ArrayBlockingQueue<List<Double>>(1);
  324. Producer p = new Producer(q);
  325. Consumer c = new Consumer(q, part.getId());
  326. Thread producer = new Thread(p);
  327. Thread consumer = new Thread(c);
  328. producer.start();
  329. consumer.start();
  330. producer.join();
  331. consumer.join();
  332. // List<Double> samples;
  333. // Epoch epoch = null;
  334. // Interval softLastISI = null;
  335. // Interval hardLastISI = null;
  336. // for (int i = 0; (samples = parser.getNextEpoch()) != null; i++) {
  337. // if (i == 0){
  338. // epoch = new Epoch(parser.getPartStartDate(), part.getId());
  339. // } else{
  340. // epoch = new Epoch(new Date(epoch.getEnd().getTime()), part.getId());
  341. // }
  342. //
  343. // epoch.setEEGSamples(samples);
  344. //
  345. // epoch.detectAndLoadSpindleIndications(parser.getSamplingRate(), group);
  346. //
  347. // softLastISI = epoch.setISIs(group, true, softLastISI);
  348. // hardLastISI = epoch.setISIs(group, false, hardLastISI);
  349. //
  350. // epochDAO.put(epoch);
  351. // }
  352. part.setEnd(c.getEnd());
  353. partDAO.put(part);
  354. audit.setImportEndTime(new Date());
  355. audit.setEegDuration(part.duration().intValue());
  356. auditDAO.put(audit);
  357. DB.commit(impTxn);
  358. log.info("Commited import transaction...");
  359. return part.getId();
  360. } catch (InterruptedException e) {
  361. throw new ApplicationException(e);
  362. }
  363. }
  364. public SortedSet<Audit> getAudits(){
  365. return auditDAO.findAllSorted();
  366. }
  367. private Person parsePerson(){
  368. return new Person(parser.getFirstName(), parser.getLastName(), null);
  369. }
  370. }