diff --git a/core/src/main/java/com/usvisatrack/core/dao/model/UscisCase.java b/core/src/main/java/com/usvisatrack/core/dao/model/UscisCase.java new file mode 100644 index 0000000..341ff0b --- /dev/null +++ b/core/src/main/java/com/usvisatrack/core/dao/model/UscisCase.java @@ -0,0 +1,89 @@ +package com.usvisatrack.core.dao.model; + +import java.util.Date; + +import com.usvisatrack.core.common.DataObject; +import com.usvisatrack.core.dao.model.data.VisaEntry; +import com.usvisatrack.core.dao.model.data.VisaStatus; + +/** + * Visa ORM + * + * @author YuCheng Hu + * + */ +public class UscisCase extends DataObject { + + private User user; + private UscisForm uscisForm; + private UscisCaseStatus uscisCaseStatus; + private String uscisCaseNumber; + private Date dateUscisCaseReceived; + private Date dateVisaIssued; + private Date dateVisaCheckCompleted; + + public UscisCase() { + Date date = new Date(); + super.setCreateDate(date); + super.setModifyDate(date); + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public UscisForm getUscisForm() { + return uscisForm; + } + + public void setUscisForm(UscisForm uscisForm) { + this.uscisForm = uscisForm; + } + + + + public UscisCaseStatus getUscisCaseStatus() { + return uscisCaseStatus; + } + + public void setUscisCaseStatus(UscisCaseStatus uscisCaseStatus) { + this.uscisCaseStatus = uscisCaseStatus; + } + + public String getUscisCaseNumber() { + return uscisCaseNumber; + } + + public void setUscisCaseNumber(String uscisCaseNumber) { + this.uscisCaseNumber = uscisCaseNumber; + } + + public Date getDateUscisCaseReceived() { + return dateUscisCaseReceived; + } + + public void setDateUscisCaseReceived(Date dateUscisCaseReceived) { + this.dateUscisCaseReceived = dateUscisCaseReceived; + } + + public Date getDateVisaIssued() { + return dateVisaIssued; + } + + public void setDateVisaIssued(Date dateVisaIssued) { + this.dateVisaIssued = dateVisaIssued; + } + + public Date getDateVisaCheckCompleted() { + return dateVisaCheckCompleted; + } + + public void setDateVisaCheckCompleted(Date dateVisaCheckCompleted) { + this.dateVisaCheckCompleted = dateVisaCheckCompleted; + } + +} diff --git a/core/src/main/java/com/usvisatrack/core/dao/model/UscisCaseStatus.java b/core/src/main/java/com/usvisatrack/core/dao/model/UscisCaseStatus.java new file mode 100644 index 0000000..9cbd1c7 --- /dev/null +++ b/core/src/main/java/com/usvisatrack/core/dao/model/UscisCaseStatus.java @@ -0,0 +1,27 @@ +package com.usvisatrack.core.dao.model; + +import com.usvisatrack.core.common.DataObject; + +/** + * UscisCaseStatus ORM + * + * @author YuCheng Hu + * + */ +public class UscisCaseStatus extends DataObject { + + private String uscisCaseStatusName; + + public UscisCaseStatus() { + + } + + public String getUscisCaseStatusName() { + return uscisCaseStatusName; + } + + public void setUscisCaseStatusName(String uscisCaseStatusName) { + this.uscisCaseStatusName = uscisCaseStatusName; + } + +} diff --git a/core/src/main/java/com/usvisatrack/core/dao/model/UscisForm.java b/core/src/main/java/com/usvisatrack/core/dao/model/UscisForm.java new file mode 100644 index 0000000..f07d282 --- /dev/null +++ b/core/src/main/java/com/usvisatrack/core/dao/model/UscisForm.java @@ -0,0 +1,36 @@ +package com.usvisatrack.core.dao.model; + +import com.usvisatrack.core.common.DataObject; + +/** + * UscisForm ORM + * + * @author YuCheng Hu + * + */ +public class UscisForm extends DataObject { + + private String uscisFormCode; + private String uscisFormName; + + public UscisForm() { + + } + + public String getUscisFormCode() { + return uscisFormCode; + } + + public void setUscisFormCode(String uscisFormCode) { + this.uscisFormCode = uscisFormCode; + } + + public String getUscisFormName() { + return uscisFormName; + } + + public void setUscisFormName(String uscisFormName) { + this.uscisFormName = uscisFormName; + } + +} diff --git a/core/src/main/java/com/usvisatrack/core/factories/UscisCaseFactory.java b/core/src/main/java/com/usvisatrack/core/factories/UscisCaseFactory.java new file mode 100644 index 0000000..f79213b --- /dev/null +++ b/core/src/main/java/com/usvisatrack/core/factories/UscisCaseFactory.java @@ -0,0 +1,120 @@ +package com.usvisatrack.core.factories; + +import java.util.List; + +import org.hibernate.Criteria; +import org.hibernate.criterion.Restrictions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.usvisatrack.core.common.Factory; +import com.usvisatrack.core.dao.model.CheckeeVisa; +import com.usvisatrack.core.dao.model.USEmbassy; +import com.usvisatrack.core.dao.model.UscisCase; +import com.usvisatrack.core.dao.model.UscisCaseStatus; +import com.usvisatrack.core.dao.model.UscisForm; +import com.usvisatrack.core.dao.model.Visa; +import com.usvisatrack.core.dao.model.VisaClass; + +/** + * Item Data Factory + * + * @author YuCheng Hu + * + */ +public class UscisCaseFactory extends Factory { + private static Logger logger = LoggerFactory.getLogger(UscisCaseFactory.class); + + private static final int LISTING_PAGE_SIZE = 20; + public static final int DEFAULT_AUTH_EXPIRATION = 10; + + /** + * + * @param uscisFormCode + * @return + */ + public static UscisCase getUscisCaseByCaseNumber(String uscisCaseNumber) { + logger.debug("Get UscisCase OBJ by form case number - [{}]", uscisCaseNumber); + + try { + Factory.beginTransaction(); + + Criteria criteria = Factory.createCriteria(UscisCase.class); + criteria.add(Restrictions.eq("uscisCaseNumber", uscisCaseNumber)); + criteria.setMaxResults(1); + + return (UscisCase) criteria.uniqueResult(); + } catch (Exception ex) { + logger.error("Search UscisCase data error", ex); + } finally { + Factory.commitTransaction(); + } + return null; + } + + /** + * Get Visa OBJ + * + * @param checkkeID + * @return + */ + public static UscisForm getUscisFormByCode(String uscisFormCode) { + logger.debug("Get UscisForm OBJ by form code - [{}]", uscisFormCode); + + try { + Factory.beginTransaction(); + + Criteria criteria = Factory.createCriteria(UscisForm.class); + criteria.add(Restrictions.ilike("uscisFormCode", "%" + uscisFormCode + "%")); + criteria.setMaxResults(1); + + return (UscisForm) criteria.uniqueResult(); + } catch (Exception ex) { + logger.error("Search UscisForm data error", ex); + } finally { + Factory.commitTransaction(); + } + return null; + } + + /** + * + * @param uscisCaseStatusName + * @return + */ + public static UscisCaseStatus getUscisCaseStatusByCode(String uscisCaseStatusName) { + logger.debug("Get UscisForm OBJ by form code - [{}]", uscisCaseStatusName); + + try { + Factory.beginTransaction(); + + Criteria criteria = Factory.createCriteria(UscisCaseStatus.class); + criteria.add(Restrictions.ilike("uscisCaseStatusName", "%" + uscisCaseStatusName + "%")); + criteria.setMaxResults(1); + + return (UscisCaseStatus) criteria.uniqueResult(); + } catch (Exception ex) { + logger.error("Search UscisForm data error", ex); + } finally { + Factory.commitTransaction(); + } + return null; + } + + /** + * Save UscisCase + * + * @param uscisCase + */ + public static void save(UscisCase uscisCase) { + try { + Factory.beginTransaction(); + Factory.saveOrUpdate(uscisCase); + Factory.commitTransaction(); + } catch (Exception ex) { + logger.error("Save UscisCase OBJ ERROR", ex); + Factory.rollbackTransaction(); + } + } + +} \ No newline at end of file diff --git a/core/src/main/resources/hbm/UscisCase.hbm.xml b/core/src/main/resources/hbm/UscisCase.hbm.xml new file mode 100644 index 0000000..bac05bc --- /dev/null +++ b/core/src/main/resources/hbm/UscisCase.hbm.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/resources/hbm/UscisCaseStatus.hbm.xml b/core/src/main/resources/hbm/UscisCaseStatus.hbm.xml new file mode 100644 index 0000000..c9991c4 --- /dev/null +++ b/core/src/main/resources/hbm/UscisCaseStatus.hbm.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + diff --git a/core/src/main/resources/hbm/UscisForm.hbm.xml b/core/src/main/resources/hbm/UscisForm.hbm.xml new file mode 100644 index 0000000..8519a12 --- /dev/null +++ b/core/src/main/resources/hbm/UscisForm.hbm.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/resources/hibernate.cfg.xml b/core/src/main/resources/hibernate.cfg.xml index cbd3b1a..3675fab 100644 --- a/core/src/main/resources/hibernate.cfg.xml +++ b/core/src/main/resources/hibernate.cfg.xml @@ -29,6 +29,9 @@ + + + diff --git a/services/src/main/java/com/usvisatrack/services/UscisCaseImporter.java b/services/src/main/java/com/usvisatrack/services/UscisCaseImporter.java new file mode 100644 index 0000000..d8619ab --- /dev/null +++ b/services/src/main/java/com/usvisatrack/services/UscisCaseImporter.java @@ -0,0 +1,254 @@ +package com.usvisatrack.services; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.joda.time.DateTime; +import org.joda.time.Days; +import org.joda.time.format.DateTimeFormat; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.usvisatrack.core.dao.model.data.UserStatus; +import com.usvisatrack.core.dao.model.data.VisaEntry; +import com.usvisatrack.core.dao.model.data.VisaStatus; +import com.usvisatrack.core.dao.model.CheckeeVisa; +import com.usvisatrack.core.dao.model.UscisCase; +import com.usvisatrack.core.dao.model.User; +import com.usvisatrack.core.dao.model.Visa; +import com.usvisatrack.core.dao.model.VisaClass; +import com.usvisatrack.core.factories.USFactory; +import com.usvisatrack.core.factories.UscisCaseFactory; +import com.usvisatrack.core.factories.UserFactory; +import com.usvisatrack.core.factories.VisaFactory; +import com.usvisatrack.services.common.DataCrawl; + +/** + * MerchandiseDataImporter to read folder in disk and import to DB + * + * @author YuCheng Hu + * + */ +public class UscisCaseImporter extends DataCrawl { + private static final Logger logger = LoggerFactory.getLogger(UscisCaseImporter.class); + + private final static String URL_USCIS_CASE = "https://egov.uscis.gov/casestatus/mycasestatus.do?appReceiptNum="; + + private static List caseNumberList = new ArrayList<>(); + + public static HashMap visaClassMap = new HashMap(); + + /** + * Command process function + */ + @Override + public void parseCommandLine(String[] args) { + options.addOption("l", true, "Clean all agents input information"); + options.addOption("h", true, "Clean one agent by input email address"); + + CommandLineParser parser = new DefaultParser(); + + // parse command line + try { + CommandLine cmd = parser.parse(options, args); + + if (cmd.hasOption("s")) { + // this.minId = Integer.parseInt(cmd.getOptionValue("l")); + // this.maxId = Integer.parseInt(cmd.getOptionValue("h")); + } + + } catch (Exception e) { + logger.warn("CLI Parse failed, using default timestamp", e); + } + } + + /** + * Run Function + */ + @Override + public void run() { + initData(); // Init data from database + + for (String caseNumber : caseNumberList) { + crawlUscisCase(URL_USCIS_CASE + caseNumber); + } + } + + /** + * crawlWebItem by parse web page + */ + private void crawlUscisCase(String cURL) { + logger.debug("Crawl USCIS Web Data to load Case info."); + + Document doc = null; + + try { + doc = Jsoup.connect(cURL).get(); + + // CASE NUMBER + String caseNumber = StringUtils.upperCase(StringUtils.substringAfterLast(cURL, "appReceiptNum=")); + + // CASE STATUS + String caseStatus = StringUtils.trimToNull(doc.select("h1").get(0).text()); + + // CASE DATE + String[] caseContentArray = StringUtils.split(doc.select("p").get(0).text(), ","); + String caseDate = StringUtils.trim(StringUtils.substringAfter(caseContentArray[0], "On")); + caseDate = caseDate + "," + StringUtils.trim(caseContentArray[1]); + DateTime dt = DateTimeFormat.forPattern("MMMMM dd,yyyy").parseDateTime(caseDate); + + // CASE FORM + String uscisFormCode = StringUtils.trim(StringUtils.substringAfter(caseContentArray[2], "Form")); + + logger.debug("Case Number / Form / Date - [{}]/[{}]/[{}]", caseNumber, uscisFormCode, dt); + + UscisCase uscisCase = new UscisCase(); + uscisCase.setUscisCaseNumber(caseNumber); + uscisCase.setUscisCaseStatus(UscisCaseFactory.getUscisCaseStatusByCode(StringUtils.capitalize(caseStatus))); + uscisCase.setUscisForm(UscisCaseFactory.getUscisFormByCode(uscisFormCode)); + uscisCase.setDateUscisCaseReceived(dt.toDate()); + + UscisCaseFactory.save(uscisCase); + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + + /** + * + */ + private void initData() { + logger.error("Init Data from Database"); + String caseNumber = "SRC1790476518"; + + String preCaseNumber = StringUtils.left(caseNumber, 8); + long ascCaseNumberDigital = NumberUtils.createLong(StringUtils.right(caseNumber, 5)); + long descCaseNumberDigital = NumberUtils.createLong(StringUtils.right(caseNumber, 5)); + + // ASC + int i = 0; + do { + ascCaseNumberDigital = ascCaseNumberDigital + 1; + String newCaseNumber = StringUtils.upperCase(preCaseNumber + Long.toString(ascCaseNumberDigital)); + UscisCase uscisCase = UscisCaseFactory.getUscisCaseByCaseNumber(newCaseNumber); + if (uscisCase == null) { + caseNumberList.add(newCaseNumber); + i++; + } else { + if (Days.daysBetween(new DateTime(), new DateTime(uscisCase.getModifyDate())).getDays() > 3) { + caseNumberList.add(newCaseNumber); + i++; + } + } + } while (i <= 500); + + // DESC + i = 0; + do { + descCaseNumberDigital = descCaseNumberDigital + 1; + String newCaseNumber = StringUtils.upperCase(preCaseNumber + Long.toString(descCaseNumberDigital)); + UscisCase uscisCase = UscisCaseFactory.getUscisCaseByCaseNumber(newCaseNumber); + if (uscisCase == null) { + caseNumberList.add(newCaseNumber); + i++; + } else { + if (Days.daysBetween(new DateTime(), new DateTime(uscisCase.getModifyDate())).getDays() > 3) { + caseNumberList.add(newCaseNumber); + i++; + } + } + } while (i <= 500); + + logger.debug("caseNumberList Size - [{}]", caseNumberList.size()); + } + + /** + * Get CheckeeCaseNumber from Checkee website + * + * @param element + * @return + */ + private String getCheckeeCaseNumber(Element element) { + String checkeeCaseNumber = null; + Element link = element.select("a").first(); + checkeeCaseNumber = StringUtils.substringAfterLast(link.attr("href"), "casenum="); + + return checkeeCaseNumber; + } + + /** + * + * @param userName + * @return + */ + private User getUser(String checkeeCaseNumber) { + String userName = null; + String userEmail = null; + + User user = null; + Document doc = null; + + try { + doc = Jsoup.connect("https://www.checkee.info/update.php?casenum=" + checkeeCaseNumber).get(); + Elements elements = doc.select("input[name=email_dis]"); + userEmail = elements.first().val(); + + elements = doc.select("b"); + userName = StringUtils.trim(StringUtils.substringAfter(elements.get(7).text(), "ID:")); + + user = UserFactory.get(userName); + if (user == null) { + user = new User(); + user.setUserName(userName); + user.setEmail(userEmail); + UserFactory.save(user); + } + + } catch (Exception e) { + // TODO: handle exception + e.printStackTrace(); + } + + return user; + } + + private void updateVisaNote(Visa visa, String checkeeCaseNumber) { + Document doc = null; + + try { + doc = Jsoup.connect("https://www.checkee.info/personal_detail.php?casenum=" + checkeeCaseNumber).get(); + Elements newsHeadlines = doc.select("table"); + Element table = newsHeadlines.get(2); + + for (Element row : table.select("tr")) { + Elements tds = row.select("td"); + String dataString = tds.get(0).text(); + if (StringUtils.startsWithIgnoreCase(dataString, "Note:")) { + visa.setDescription(StringUtils.trimToEmpty(StringUtils.substringAfter(dataString, "Note:"))); + } + } + + } catch (Exception e) { + // TODO: handle exception + e.printStackTrace(); + } + + logger.debug("Case Description - [{}]", visa.getDescription()); + } + +}