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