package gov.nysenate.openleg.processor.calendar; import com.google.common.base.Strings; import gov.nysenate.openleg.model.base.Version; import gov.nysenate.openleg.model.bill.BillId; import gov.nysenate.openleg.model.calendar.*; import gov.nysenate.openleg.model.process.DataProcessUnit; import gov.nysenate.openleg.model.sobi.SobiFragment; import gov.nysenate.openleg.model.sobi.SobiFragmentType; import gov.nysenate.openleg.processor.base.AbstractDataProcessor; import gov.nysenate.openleg.processor.sobi.SobiProcessor; import gov.nysenate.openleg.util.DateUtils; import gov.nysenate.openleg.util.XmlHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import javax.annotation.PostConstruct; import javax.xml.xpath.XPathExpressionException; import java.io.IOException; import java.time.LocalDate; import java.time.LocalDateTime; @Service public class CalendarProcessor extends AbstractDataProcessor implements SobiProcessor { private static final Logger logger = LoggerFactory.getLogger(CalendarProcessor.class); @Autowired protected XmlHelper xml; @PostConstruct public void init() { initBase(); } @Override public SobiFragmentType getSupportedType() { return SobiFragmentType.CALENDAR; } @Override public void process(SobiFragment sobiFragment) { logger.info("Processing Senate Calendar... {}", sobiFragment.getFragmentId()); LocalDateTime modifiedDate = sobiFragment.getPublishedDateTime(); DataProcessUnit unit = createProcessUnit(sobiFragment); try { Document doc = xml.parse(sobiFragment.getText()); Node xmlCalendar = xml.getNode("SENATEDATA/sencalendar", doc); Integer calendarNo = xml.getInteger("@no", xmlCalendar); Integer sessionYear = xml.getInteger("@sessyr", xmlCalendar); Integer year = xml.getInteger("@year", xmlCalendar); CalendarId calendarId = new CalendarId(calendarNo, year); Calendar calendar = getOrCreateCalendar(calendarId, sobiFragment); calendar.setModifiedDateTime(modifiedDate); // Actions apply to supplemental and not the whole calendar String action = xml.getString("@action", xmlCalendar); NodeList xmlSupplementals = xml.getNodeList("supplemental", xmlCalendar); for (int i = 0; i < xmlSupplementals.getLength(); i++) { Node xmlSupplemental = xmlSupplementals.item(i); Version supVersion = Version.of(xml.getString("@id", xmlSupplemental)); if (action.equalsIgnoreCase("remove")) { calendar.removeSupplemental(supVersion); } else { // Replace this supplemental LocalDate calDate = DateUtils.getLrsLocalDate(xml.getString("caldate/text()", xmlSupplemental)); LocalDateTime releaseDateTime = DateUtils.getLrsDateTime(xml.getString("releasedate/text()", xmlSupplemental) + xml.getString("releasetime/text()", xmlSupplemental)); CalendarSupplemental supplemental = new CalendarSupplemental(calendarId, supVersion, calDate, releaseDateTime); supplemental.setModifiedDateTime(modifiedDate); supplemental.setPublishedDateTime(modifiedDate); NodeList xmlSections = xml.getNodeList("sections/section", xmlSupplemental); for (int j = 0; j < xmlSections.getLength(); j++) { Node xmlSection = xmlSections.item(j); Integer cd = xml.getInteger("@cd", xmlSection); CalendarSectionType sectionType = CalendarSectionType.valueOfCode(cd); NodeList xmlCalNos = xml.getNodeList("calnos/calno", xmlSection); for (int k = 0; k < xmlCalNos.getLength(); k++) { Node xmlCalNo = xmlCalNos.item(k); Integer no = xml.getInteger("@no", xmlCalNo); String billPrintNo = xml.getString("bill/@no", xmlCalNo); BillId billId = new BillId(billPrintNo, sessionYear); boolean billHigh = xml.getString("bill/@high", xmlCalNo).equals("true"); String subBillPrintNo = xml.getString("subbill/@no", xmlCalNo); BillId subBillId = (!Strings.isNullOrEmpty(subBillPrintNo)) ? new BillId(subBillPrintNo, sessionYear) : null; CalendarSupplementalEntry entry = new CalendarSupplementalEntry(no, sectionType, billId, subBillId, billHigh); supplemental.addEntry(entry); } } calendar.putSupplemental(supplemental); } } } catch (IOException | SAXException | XPathExpressionException ex) { logger.error("Failed to parse calendar sobi {}", sobiFragment.getFragmentId(), ex); unit.addException("Failed to parse calendar: " + ex.getMessage()); } // Notify the data processor that a calendar fragment has finished processing postDataUnitEvent(unit); if (!env.isSobiBatchEnabled() || calendarIngestCache.exceedsCapacity()) { flushCalendarUpdates(); } } @Override public void postProcess() { flushCalendarUpdates(); } }