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());
+ }
+
+}