gov.medicaid.screening.dao.impl.OIGDAOBean.java Source code

Java tutorial

Introduction

Here is the source code for gov.medicaid.screening.dao.impl.OIGDAOBean.java

Source

/*
 * Copyright (C) 2012 TopCoder Inc., All Rights Reserved.
 */
package gov.medicaid.screening.dao.impl;

import gov.medicaid.entities.Address;
import gov.medicaid.entities.Business;
import gov.medicaid.entities.ExclusionType;
import gov.medicaid.entities.OIGSearchCriteria;
import gov.medicaid.entities.ProviderProfile;
import gov.medicaid.entities.SearchResult;
import gov.medicaid.entities.Specialty;
import gov.medicaid.entities.User;
import gov.medicaid.screening.dao.OIGDAO;
import gov.medicaid.screening.services.ErrorCode;
import gov.medicaid.screening.services.ParsingException;
import gov.medicaid.screening.services.ServiceException;
import gov.medicaid.screening.services.impl.LogUtil;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 * This defines the logic for scraping OIG exclusion results.
 *
 * @author j3_guile
 * @version 1.0
 */
@Stateless
@Local(OIGDAO.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class OIGDAOBean extends BaseDAO implements OIGDAO {

    /**
     * The supported columns for this implementation.
     */
    private static final Map<String, String> SORT_COLUMNS = new HashMap<String, String>() {
        {
            put("firstName", "profile.user.firstName");
            put("middleName", "profile.user.middleName");
            put("lastName", "profile.user.lastName");
            put("type", "type.name");
            put("originalIssueDate", "originalIssueDate");
            put("expireDate", "expireDate");
            put("renewalDate", "renewalDate");
            put("licenseNumber", "licenseNumber");
        }
    };

    /**
     * Host used for search.
     */
    @Resource(name = "mita/config/verificationURL")
    private String verificationURL;

    /**
     * Host used for search.
     */
    @Resource(name = "mita/config/exclusionURL")
    private String exclusionURL;

    /**
     * Date format used by this source.
     */
    private static final String DATE_FORMAT = "MM/dd/yyyy";

    /**
     * Default empty constructor.
     */
    public OIGDAOBean() {
    }

    /**
     * Searches for excluded providers.
     *
     * @param criteria the search criteria
     * @return the matched results
     * @throws ParsingException if any parsing errors are encountered
     * @throws ServiceException for any other exceptions encountered
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public SearchResult<ProviderProfile> search(OIGSearchCriteria criteria)
            throws ParsingException, ServiceException {
        String signature = "OIGDataAccessImpl#search";
        LogUtil.traceEntry(getLog(), signature, new String[] { "criteria" }, new Object[] { criteria });

        if (criteria == null || (Util.isBlank(criteria.getLastName()) && Util.isBlank(criteria.getFirstName())
                && Util.isBlank(criteria.getBusinessName()))) {
            throw new ServiceException(ErrorCode.MITA10005.getDesc());
        }

        validateSortOptions(criteria, SORT_COLUMNS);

        try {
            SearchResult<ProviderProfile> allResults = getAllResults(criteria);
            SearchResult<ProviderProfile> results = trimResults(allResults, criteria.getPageSize(),
                    criteria.getPageNumber(), SORT_COLUMNS.get(criteria.getSortColumn()), criteria.getSortOrder());

            logSearchEntry(criteria);
            return results;
        } catch (ClientProtocolException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        } catch (URISyntaxException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        } catch (IOException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        } catch (ParseException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        }
    }

    /**
     * Verifies SSN if valid.
     *
     * @param entityId the entity id
     * @param ssn the ssn
     * @return true if valid, false if not
     * @throws ParsingException if any parsing errors are encountered
     * @throws ServiceException for any other exceptions encountered
     *
     * @deprecated not updated in new site layout.
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Deprecated
    public boolean verifySSN(String entityId, String ssn) throws ParsingException, ServiceException {
        String signature = "OIGDataAccessImpl#verifySSN";
        LogUtil.traceEntry(getLog(), signature, new String[] { "entityId", "ssn" }, new Object[] { entityId, ssn });

        if (Util.isBlank(entityId) && Util.isBlank(ssn)) {
            throw new ServiceException(ErrorCode.MITA10005.getDesc());
        }

        try {
            return LogUtil.traceExit(getLog(), signature, checkSSN(entityId, ssn));
        } catch (ClientProtocolException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        } catch (IOException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        }
    }

    /**
     * Retrieves all available exclusion types.
     *
     * @return the exclusion types.
     * @throws ParsingException if any parsing errors are encountered
     * @throws ServiceException for any other exceptions encountered
     *
     * @deprecated not updated in new site layout.
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Deprecated
    public List<ExclusionType> getExclusionTypeList() throws ParsingException, ServiceException {
        String signature = "OIGDataAccessImpl#verifySSN";
        LogUtil.traceEntry(getLog(), signature, new String[] {}, new Object[] {});

        try {
            return LogUtil.traceExit(getLog(), signature, getAllExclusions());
        } catch (ClientProtocolException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        } catch (URISyntaxException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        } catch (IOException e) {
            LogUtil.traceError(getLog(), signature, e);
            throw new ServiceException(ErrorCode.MITA50001.getDesc(), e);
        }
    }

    /**
     * Performs a search for all exclusion types.
     *
     * @return the search result for provider profiles
     *
     * @throws URISyntaxException if an error occurs while building the URL.
     * @throws ClientProtocolException if client does not support protocol used.
     * @throws IOException if an error occurs while parsing response.
     * @throws ServiceException for any other problems encountered
     *
     * @deprecated not updated in new site layout.
     */
    @Deprecated
    private List<ExclusionType> getAllExclusions()
            throws URISyntaxException, ClientProtocolException, IOException, ServiceException {
        DefaultHttpClient client = new DefaultHttpClient();

        HttpGet getSearch = new HttpGet(new URIBuilder(getExclusionURL()).build());
        HttpResponse response = client.execute(getSearch);

        verifyAndAuditCall(getExclusionURL(), response);

        Document page = Jsoup.parse(EntityUtils.toString(response.getEntity()));
        List<ExclusionType> allExclusions = new ArrayList<ExclusionType>();

        Elements links = page.select("table#CountList tbody tr td a");
        for (Element link : links) {
            ExclusionType exclusionType = new ExclusionType();
            exclusionType.setName(link.text());
            allExclusions.add(exclusionType);
        }
        return allExclusions;
    }

    /**
     * Performs a search for all possible results.
     *
     * @param criteria The search criteria.
     * @return the search result for provider profiles
     *
     * @throws URISyntaxException if an error occurs while building the URL.
     * @throws ClientProtocolException if client does not support protocol used.
     * @throws IOException if an error occurs while parsing response.
     * @throws ParseException if an error occurs while parsing response.
     * @throws ServiceException for any other problems encountered
     */
    private SearchResult<ProviderProfile> getAllResults(OIGSearchCriteria criteria)
            throws URISyntaxException, ClientProtocolException, IOException, ParseException, ServiceException {
        DefaultHttpClient client = new DefaultHttpClient(getLaxSSLConnectionManager());
        client.setRedirectStrategy(new LaxRedirectStrategy());

        HttpGet getSearch = new HttpGet(new URIBuilder(getSearchURL()).build());
        HttpResponse response = client.execute(getSearch);

        verifyAndAuditCall(getSearchURL(), response);

        Document page = Jsoup.parse(EntityUtils.toString(response.getEntity()));
        HttpPost search = new HttpPost(new URIBuilder(getSearchURL()).build());
        List<ProviderProfile> allProfiles = new ArrayList<ProviderProfile>();

        boolean entitySearch = (Util.isBlank(criteria.getLastName()) && Util.isBlank(criteria.getFirstName()));

        HttpEntity entity = null;
        if (!entitySearch) {
            entity = postForm(getSearchURL(), client, search,
                    new String[][] { { "__EVENTARGUMENT", "" }, { "__EVENTTARGET", "" },
                            { "__EVENTVALIDATION", page.select("input[name=__EVENTVALIDATION]").first().val() },
                            { "__VIEWSTATE", page.select("input[name=__VIEWSTATE]").first().val() },
                            { "ctl00$cpExclusions$ibSearchSP.x", "0" }, { "ctl00$cpExclusions$ibSearchSP.y", "0" },
                            { "ctl00$cpExclusions$txtSPLastName", Util.defaultString(criteria.getLastName()) },
                            { "ctl00$cpExclusions$txtSPFirstName", Util.defaultString(criteria.getFirstName()) } },
                    false);
        } else {
            HttpEntity searchEntity = postForm(getSearchURL(), client, search, new String[][] {
                    { "__EVENTARGUMENT", "" }, { "__EVENTTARGET", "ctl00$cpExclusions$Linkbutton1" },
                    { "__EVENTVALIDATION", page.select("input[name=__EVENTVALIDATION]").first().val() },
                    { "__VIEWSTATE", page.select("input[name=__VIEWSTATE]").first().val() },
                    { "ctl00$cpExclusions$txtSPLastName", "" }, { "ctl00$cpExclusions$txtSPFirstName", "" } },
                    false);

            page = Jsoup.parse(EntityUtils.toString(searchEntity));

            entity = postForm(getSearchURL(), client, search,
                    new String[][] { { "__EVENTARGUMENT", "" }, { "__EVENTTARGET", "" },
                            { "__EVENTVALIDATION", page.select("input[name=__EVENTVALIDATION]").first().val() },
                            { "__VIEWSTATE", page.select("input[name=__VIEWSTATE]").first().val() },
                            { "ctl00$cpExclusions$ibSearchSP.x", "0" }, { "ctl00$cpExclusions$ibSearchSP.y", "0" },
                            { "ctl00$cpExclusions$txtSBName", Util.defaultString(criteria.getBusinessName()) } },
                    false);
        }

        page = Jsoup.parse(EntityUtils.toString(entity));

        Elements rows;
        int ssnColumnIndex;
        if (!entitySearch) {
            rows = page.select("table#ctl00_cpExclusions_gvEmployees tr:gt(0)");
            ssnColumnIndex = 7;
        } else {
            rows = page.select("table#ctl00_cpExclusions_gvBusiness tr:gt(0)");
            ssnColumnIndex = 5;
        }

        for (Element row : rows) {
            String href;
            if (row.select("td:eq(" + ssnColumnIndex + ")").text().equals("N/A")) {
                href = row.select("td:eq(0) a").first().attr("href");
            } else {
                href = row.select("td:eq(" + ssnColumnIndex + ") a").first().attr("href");
            }

            href = href.replaceFirst("javascript:__doPostBack\\('", "");
            href = href.replaceFirst("',''\\)", "");

            ProviderProfile profile = parseProfile(getDetails(client, href, page));
            String entityId = href.substring(0, href.lastIndexOf('$'));
            entityId = entityId.substring(entityId.lastIndexOf('$') + 4);
            profile.setId(Long.parseLong(entityId) - 2);
            allProfiles.add(profile);
        }

        SearchResult<ProviderProfile> searchResult = new SearchResult<ProviderProfile>();
        searchResult.setItems(allProfiles);
        return searchResult;
    }

    /**
     * Get details page.
     *
     * @param client the default http client
     * @param target the target PostBack
     * @param searchPage the search page
     * @return the details page
     * @throws ClientProtocolException if client does not support protocol used.
     * @throws IOException if an error occurs while parsing response.
     * @throws ServiceException for any other problems encountered
     */
    private Document getDetails(DefaultHttpClient client, String target, Document searchPage)
            throws ClientProtocolException, IOException, ServiceException {
        String detailURL = Util.replaceLastURLPart(getSearchURL(), "SearchResults.aspx");
        HttpPost getDetail = new HttpPost(detailURL);
        HttpEntity entity = null;
        try {
            entity = postForm(detailURL, client, getDetail,
                    new String[][] { { "__EVENTARGUMENT", "" }, { "__EVENTTARGET", target },
                            { "__EVENTVALIDATION",
                                    searchPage.select("input[name=__EVENTVALIDATION]").first().val() },
                            { "__VIEWSTATE", searchPage.select("input[name=__VIEWSTATE]").first().val() } },
                    false);

        } catch (ServiceException e) {
            try {
                // try https redirection before throwing exception
                detailURL = Util.replaceLastURLPart(getSearchURL(), "Verify.aspx");
                detailURL = detailURL.replaceFirst("http", "https");
                HttpGet getDetails = new HttpGet(new URIBuilder(detailURL).build());
                HttpResponse response = client.execute(getDetails);
                verifyAndAuditCall(detailURL, response);
                entity = response.getEntity();

            } catch (Exception e1) {
                throw new ServiceException(ErrorCode.MITA50001.getDesc(), e1);
            }
        }
        return Jsoup.parse(EntityUtils.toString(entity));
    }

    /**
     * Get details page.
     *
     * @param client the default http client
     * @param entityId the entity id
     * @return the details page
     * @throws ClientProtocolException if client does not support protocol used.
     * @throws IOException if an error occurs while parsing response.
     * @throws ServiceException for any other problems encountered
     *
     * @deprecated not updated in new site layout.
     */
    @Deprecated
    private Document getDetails(DefaultHttpClient client, String entityId)
            throws ClientProtocolException, IOException, ServiceException {
        String detailURL = Util.replaceLastURLPart(getSearchURL(), "Verification.aspx");
        HttpGet getDetail = new HttpGet(detailURL);
        getDetail.setHeader(new BasicHeader("Cookie", "Entity=" + entityId));

        HttpResponse detailsResponse = client.execute(getDetail);
        verifyAndAuditCall(detailURL, detailsResponse);
        return Jsoup.parse(EntityUtils.toString(detailsResponse.getEntity()));
    }

    /**
     * Verifies if the provided SSN is valid for the given entity id.
     *
     * @param entityId the entity id
     * @param ssn the ssn to be verified
     * @return true if valid, false if not
     * @throws ClientProtocolException if client does not support protocol used.
     * @throws IOException if an error occurs while parsing response.
     * @throws ServiceException for any other problems encountered
     *
     * @deprecated not updated in new site layout.
     */
    @Deprecated
    private boolean checkSSN(String entityId, String ssn) throws IOException, ServiceException {
        DefaultHttpClient client = new DefaultHttpClient(getLaxSSLConnectionManager());
        client.setRedirectStrategy(new LaxRedirectStrategy());
        return executeVerification(client, entityId, ssn, getDetails(client, entityId));
    }

    /**
     * Verify if SSN is correct.
     *
     * @param client the default http client
     * @param entityId the entity id
     * @param ssn the ssn to be verified
     * @param profileDetails the details page
     * @return true if verified, false if not
     * @throws ClientProtocolException if client does not support protocol used.
     * @throws IOException if an error occurs while parsing response.
     * @throws ServiceException for any other problems encountered
     *
     * @deprecated not updated in new site layout.
     */
    @Deprecated
    private boolean executeVerification(DefaultHttpClient client, String entityId, String ssn,
            Document profileDetails) throws ClientProtocolException, IOException, ServiceException {
        HttpPost verifyDetails = new HttpPost(getVerificationURL());
        verifyDetails.setHeader(new BasicHeader("Cookie", "Entity=" + entityId));

        HttpEntity verifiedEntity = postForm(getVerificationURL(), client, verifyDetails,
                new String[][] { { "cmdVerify", "Verify" }, { "txtIdInput", ssn },
                        { "__VIEWSTATE", profileDetails.select("input[name=__VIEWSTATE]").first().val() } },
                true);

        Document verifiedDetails = Jsoup.parse(EntityUtils.toString(verifiedEntity));
        String message = verifiedDetails.select("#lblVerifyConfirm").text();
        return message.indexOf("This record does NOT match SSN/EIN") == -1;
    }

    /**
     * Parses the excluded provider profile details page.
     *
     * @param page the details page
     * @return the parsed license details
     * @throws ParsingException if the expected tags were not found
     */
    private ProviderProfile parseProfile(Document page) throws ParsingException {
        ProviderProfile profile = new ProviderProfile();

        // name
        User user = new User();
        profile.setUser(user);
        user.setLastName(page.select("th:containsOwn(Last Name) + td").text());
        user.setFirstName(page.select("th:containsOwn(First Name) + td").text());

        // business
        String businessName = page.select("th:containsOwn(Entity) + td").text();
        if (!"N/A".equals(businessName)) {
            Business business = new Business();
            profile.setBusiness(business);
            business.setName(businessName);
        }

        // DOB
        Date dob = parseDate(page.select("th:has(acronym:containsOwn(DOB)) + td").text(), DATE_FORMAT);
        if (dob != null) {
            profile.setDob(dob);
        }

        // exclusion type
        ExclusionType exclusionType = new ExclusionType();
        profile.setExclusionType(exclusionType);
        exclusionType.setName(page.select("th:containsOwn(Excl. Type) + td").text());

        // specialty
        List<Specialty> specialties = new ArrayList<Specialty>();
        Specialty specialty = new Specialty();
        specialties.add(specialty);
        specialty.setName(page.select("th:containsOwn(Specialty) + td").text());
        profile.setSpecialties(specialties);

        // address
        Elements addrElement = page.select("th:containsOwn(Address) + td");
        String addr = addrElement.text();
        Element addrNextRow = addrElement.parents().first().nextElementSibling();
        if ("".equals(addrNextRow.select("th").text())) {
            addr += " " + addrNextRow.select("td").text();
        }
        Address address = new Address();
        address.setLocation(addr);
        profile.setAddresses(Arrays.asList(new Address[] { address }));

        Date date = parseDate(page.select("th:containsOwn(Excl. Date) + td").text(), DATE_FORMAT);
        if (date != null) {
            profile.setRequestEffectiveDate(date);
        }

        return profile;
    }

    public String getExclusionURL() {
        return exclusionURL != null ? exclusionURL : jndiGet("java:comp/env/mita/config/exclusionURL");
    }

    public String getVerificationURL() {
        return verificationURL != null ? verificationURL : jndiGet("java:comp/env/mita/config/verificationURL");
    }
}