1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.ole.coa.service.impl;
17
18 import java.io.BufferedReader;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.util.Calendar;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.SortedMap;
28 import java.util.TreeMap;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.commons.net.ftp.FTPClient;
32 import org.apache.commons.net.ftp.FTPReply;
33 import org.kuali.ole.coa.batch.CfdaBatchStep;
34 import org.kuali.ole.coa.businessobject.CFDA;
35 import org.kuali.ole.coa.businessobject.CfdaUpdateResults;
36 import org.kuali.ole.coa.service.CfdaService;
37 import org.kuali.ole.sys.OLEConstants;
38 import org.kuali.ole.sys.context.SpringContext;
39 import org.kuali.rice.core.api.datetime.DateTimeService;
40 import org.kuali.rice.coreservice.framework.parameter.ParameterService;
41 import org.kuali.rice.krad.service.BusinessObjectService;
42
43 import au.com.bytecode.opencsv.CSVReader;
44
45 public class CfdaServiceImpl implements CfdaService {
46 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(CfdaServiceImpl.class);
47
48 protected BusinessObjectService businessObjectService;
49 protected static Comparator cfdaComparator;
50
51 static {
52 cfdaComparator = new Comparator() {
53 @Override
54 public int compare(Object o1, Object o2) {
55 String lhs = (String) o1;
56 String rhs = (String) o2;
57 return lhs.compareTo(rhs);
58 }
59 };
60 }
61
62
63
64
65
66 public SortedMap<String, CFDA> getGovCodes() throws IOException {
67 Calendar calendar = SpringContext.getBean(DateTimeService.class).getCurrentCalendar();
68 SortedMap<String, CFDA> govMap = new TreeMap<String, CFDA>();
69
70
71 String govURL = SpringContext.getBean(ParameterService.class).getParameterValueAsString(CfdaBatchStep.class, OLEConstants.SOURCE_URL_PARAMETER);
72 String fileName = StringUtils.substringAfterLast(govURL, "/");
73 govURL = StringUtils.substringBeforeLast(govURL, "/");
74 if (StringUtils.contains(govURL, "ftp://")) {
75 govURL = StringUtils.remove(govURL, "ftp://");
76 }
77
78
79 String year = "" + calendar.get(Calendar.YEAR);
80 year = year.substring(2, 4);
81 fileName = fileName + year;
82
83
84 fileName = fileName + String.format("%03d", calendar.get(Calendar.DAY_OF_YEAR) - 1);
85 fileName = fileName + ".csv";
86
87 LOG.info("Getting government file: " + fileName + " for update");
88
89 InputStream inputStream = null;
90 FTPClient ftp = new FTPClient();
91 try {
92 ftp.connect(govURL);
93 int reply = ftp.getReplyCode();
94
95 if (!FTPReply.isPositiveCompletion(reply)) {
96 LOG.error("FTP connection to server not established.");
97 throw new IOException("FTP connection to server not established.");
98 }
99
100 boolean loggedIn = ftp.login("anonymous", "");
101 if (!loggedIn) {
102 LOG.error("Could not login as anonymous.");
103 throw new IOException("Could not login as anonymous.");
104 }
105
106 LOG.info("Successfully connected and logged in");
107 ftp.enterLocalPassiveMode();
108 inputStream = ftp.retrieveFileStream(fileName);
109 if (inputStream != null) {
110 LOG.info("reading input stream");
111 InputStreamReader screenReader = new InputStreamReader(inputStream);
112 BufferedReader screen = new BufferedReader(screenReader);
113
114 CSVReader csvReader = new CSVReader(screenReader, ',', '"', 1);
115 List<String[]> lines = csvReader.readAll();
116 for (String[] line : lines) {
117 String title = line[0];
118 String number = line[1];
119
120 CFDA cfda = new CFDA();
121 cfda.setCfdaNumber(number);
122 cfda.setCfdaProgramTitleName(title);
123
124 govMap.put(number, cfda);
125 }
126 }
127
128 ftp.logout();
129 ftp.disconnect();
130 }
131 finally {
132 if (ftp.isConnected()) {
133 ftp.disconnect();
134 }
135 }
136
137 return govMap;
138 }
139
140
141
142
143
144 public SortedMap<String, CFDA> getKfsCodes() throws IOException {
145 Collection allCodes = businessObjectService.findAll(CFDA.class);
146
147 SortedMap<String, CFDA> kfsMapAll = new TreeMap<String, CFDA>(cfdaComparator);
148 for (Object o : allCodes) {
149 CFDA c = (CFDA) o;
150 kfsMapAll.put(c.getCfdaNumber(), c);
151 }
152 return kfsMapAll;
153 }
154
155
156
157
158 @Override
159 public CfdaUpdateResults update() throws IOException {
160
161 CfdaUpdateResults results = new CfdaUpdateResults();
162 Map<String, CFDA> govMap = null;
163
164 try {
165 govMap = getGovCodes();
166 }
167 catch (IOException ioe) {
168 LOG.error("Error connecting to URL resource: " + ioe.getMessage(), ioe);
169 StringBuilder builder = new StringBuilder();
170 builder.append("No updates took place.\n");
171 builder.append(ioe.getMessage());
172 results.setMessage(builder.toString());
173 return results;
174 }
175 Map<String, CFDA> kfsMap = getKfsCodes();
176
177 results.setNumberOfRecordsInKfsDatabase(kfsMap.keySet().size());
178 results.setNumberOfRecordsRetrievedFromWebSite(govMap.keySet().size());
179
180 for (Object key : kfsMap.keySet()) {
181
182 CFDA cfdaKfs = kfsMap.get(key);
183 CFDA cfdaGov = govMap.get(key);
184
185 if (cfdaKfs.getCfdaMaintenanceTypeId().startsWith("M")) {
186
187 results.setNumberOfRecordsNotUpdatedBecauseManual(1 + results.getNumberOfRecordsNotUpdatedBecauseManual());
188 }
189 else if (cfdaKfs.getCfdaMaintenanceTypeId().startsWith("A")) {
190
191 if (cfdaGov == null) {
192 if (cfdaKfs.isActive()) {
193 cfdaKfs.setActive(false);
194 businessObjectService.save(cfdaKfs);
195 results.setNumberOfRecordsDeactivatedBecauseNoLongerOnWebSite(results.getNumberOfRecordsDeactivatedBecauseNoLongerOnWebSite() + 1);
196 }
197 else {
198
199 results.setNumberOfRecrodsNotUpdatedForHistoricalPurposes(results.getNumberOfRecrodsNotUpdatedForHistoricalPurposes() + 1);
200 }
201 }
202 else {
203 if (cfdaKfs.isActive()) {
204 results.setNumberOfRecordsUpdatedBecauseAutomatic(results.getNumberOfRecordsUpdatedBecauseAutomatic() + 1);
205 }
206 else {
207 cfdaKfs.setActive(true);
208 results.setNumberOfRecordsReActivated(results.getNumberOfRecordsReActivated() + 1);
209 }
210
211 cfdaKfs.setCfdaProgramTitleName(cfdaGov.getCfdaProgramTitleName());
212 businessObjectService.save(cfdaKfs);
213 }
214 }
215
216
217 govMap.remove(key);
218 }
219
220
221 for (String key : govMap.keySet()) {
222 CFDA cfdaGov = govMap.get(key);
223 cfdaGov.setCfdaMaintenanceTypeId("AUTOMATIC");
224 cfdaGov.setActive(true);
225 businessObjectService.save(cfdaGov);
226 results.setNumberOfRecordsNewlyAddedFromWebSite(results.getNumberOfRecordsNewlyAddedFromWebSite() + 1);
227 }
228
229 return results;
230 }
231
232 public void setBusinessObjectService(BusinessObjectService businessObjectService) {
233 this.businessObjectService = businessObjectService;
234 }
235
236 @Override
237 public CFDA getByPrimaryId(String cfdaNumber) {
238 if (StringUtils.isBlank(cfdaNumber)) {
239 return null;
240 }
241 return businessObjectService.findBySinglePrimaryKey(CFDA.class, cfdaNumber.trim());
242 }
243
244 }