net.kevxu.purdueassist.course.CatalogDetail.java Source code

Java tutorial

Introduction

Here is the source code for net.kevxu.purdueassist.course.CatalogDetail.java

Source

/*
 * CatalogDetail.java
 * 
 * Written by Kaiwen Xu (kevin) and Rendong Chen (ryan).
 * Released under Apache License 2.0.
 */

package net.kevxu.purdueassist.course;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import net.kevxu.purdueassist.course.elements.Predefined.Subject;
import net.kevxu.purdueassist.course.elements.Predefined.Term;
import net.kevxu.purdueassist.course.elements.Predefined.Type;
import net.kevxu.purdueassist.course.shared.CourseNotFoundException;
import net.kevxu.purdueassist.course.shared.HtmlParseException;
import net.kevxu.purdueassist.course.shared.RequestNotFinishedException;
import net.kevxu.purdueassist.shared.httpclient.BasicHttpClientAsync;
import net.kevxu.purdueassist.shared.httpclient.BasicHttpClientAsync.HttpRequestListener;
import net.kevxu.purdueassist.shared.httpclient.HttpClientAsync.HttpMethod;
import net.kevxu.purdueassist.shared.httpclient.MethodNotPostException;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 * This is the class implementing "Catalog Detail" search described in the
 * document. It utilizes asynchronous function call for non-blocking calling
 * style. You have to provide callback method by implementing
 * CatalogDetailListener.
 * <p>
 * Input: subject cnbr <br />
 * Input (optional): term
 * <p>
 * Output: <br />
 * subject cnbr name description levels type offeredBy department campuses
 * restrictions prerequisites
 * 
 * @author Rendong Chen (ryan), Kaiwen Xu (kevin)
 * @see CatalogDetailListener
 */
public class CatalogDetail implements HttpRequestListener {

    private static final String URL_HEAD = "https://selfservice.mypurdue.purdue.edu/prod/"
            + "bzwsrch.p_catalog_detail";

    private Term term;
    private Subject subject;
    private int cnbr;

    private CatalogDetailListener mListener;
    private BasicHttpClientAsync httpClient;

    private boolean requestFinished;

    public interface CatalogDetailListener {
        public void onCatalogDetailFinished(CatalogDetailEntry entry);

        public void onCatalogDetailFinished(IOException e);

        public void onCatalogDetailFinished(HtmlParseException e);

        public void onCatalogDetailFinished(CourseNotFoundException e);

        public void onCatalogDetailFinished(Exception e);
    }

    public CatalogDetail(CatalogDetailListener catalogDetailListener) {
        this.mListener = catalogDetailListener;
        this.requestFinished = true;
    }

    public void getResult(Subject subject, int cnbr) throws RequestNotFinishedException {
        getResult(Term.CURRENT, subject, cnbr);
    }

    public void getResult(Term term, Subject subject, int cnbr) throws RequestNotFinishedException {
        if (!this.requestFinished)
            throw new RequestNotFinishedException();

        this.requestFinished = false;

        if (term == null)
            term = Term.CURRENT;

        this.term = term;
        this.subject = subject;
        this.cnbr = cnbr;

        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
        parameters.add(new BasicNameValuePair("term", term.getLinkName()));
        parameters.add(new BasicNameValuePair("subject", subject.name()));
        parameters.add(new BasicNameValuePair("cnbr", Integer.toString(cnbr)));

        httpClient = new BasicHttpClientAsync(URL_HEAD, HttpMethod.POST, this);
        try {
            httpClient.setParameters(parameters);
            httpClient.getResponse();
        } catch (MethodNotPostException e) {
            e.printStackTrace();
        } finally {
            this.requestFinished = true;
        }
    }

    /**
     * Check whether previous request has been finished.
     * 
     * @return Return true if previous request has already finished.
     */
    public boolean isRequestFinished() {
        return this.requestFinished;
    }

    @Override
    public void onRequestFinished(HttpResponse httpResponse) {
        try {
            InputStream stream = httpResponse.getEntity().getContent();
            Header encoding = httpResponse.getEntity().getContentEncoding();
            Document document;
            if (encoding == null) {
                document = Jsoup.parse(stream, null, URL_HEAD);
            } else {
                document = Jsoup.parse(stream, encoding.getValue(), URL_HEAD);
            }
            stream.close();
            CatalogDetailEntry entry = parseDocument(document);
            mListener.onCatalogDetailFinished(entry);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            mListener.onCatalogDetailFinished(e);
        } catch (HtmlParseException e) {
            mListener.onCatalogDetailFinished(e);
        } catch (CourseNotFoundException e) {
            mListener.onCatalogDetailFinished(e);
        } catch (Exception e) {
            mListener.onCatalogDetailFinished(e);
        } finally {
            this.requestFinished = true;
        }
    }

    @Override
    public void onRequestFinished(ClientProtocolException e) {
        e.printStackTrace();
        this.requestFinished = true;
    }

    @Override
    public void onRequestFinished(IOException e) {
        mListener.onCatalogDetailFinished(e);
        this.requestFinished = true;
    }

    private CatalogDetailEntry parseDocument(Document document)
            throws HtmlParseException, CourseNotFoundException, IOException {
        CatalogDetailEntry entry = new CatalogDetailEntry(subject, cnbr);
        Elements tableElements = document.getElementsByAttributeValue("summary",
                "This table lists the course detail for the selected term.");
        if (tableElements.isEmpty() != true) {
            // get name
            try {
                Element body = tableElements.first().select("tbody").first();
                String nameBlock = body.select("tr td.nttitle").first().text();
                String[] temp = nameBlock.split(subject.name() + " " + String.valueOf(cnbr));
                String name = temp[temp.length - 1].substring(3);
                entry.setName(name);

                // get description
                body = body.select(".ntdefault").first();
                String text = body.text();
                int split = text.indexOf("Levels:");
                String description = text.substring(0, split);
                description = description.substring(20);
                entry.setDescription(description);

                // get levels
                int begin = split;
                int end = text.indexOf("Schedule Types:");
                String levels = text.substring(begin + 8, end);
                temp = levels.split("[ ,]");
                List<String> lvs = new ArrayList<String>();
                for (String s : temp)
                    if (!s.equals("")) {
                        lvs.add(s);
                    }
                entry.setLevels(lvs);

                // get type and prerequisites
                List<Type> types = new ArrayList<Type>();
                List<String> preq = new ArrayList<String>();
                Elements parsing_A = body.select("a");
                for (Element e : parsing_A) {
                    if (e.attr("href").contains("schd_in") && !(e.attr("href").contains("%"))) {

                        try {
                            types.add(Type.valueOf(e.text().replace(" ", "")));
                        } catch (Exception exception) {
                            throw new HtmlParseException();
                        }
                    } else if (e.attr("href").contains("sel_attr=")) {
                        preq.add(e.text());
                    }
                }
                if (types.size() > 0)
                    entry.setType(types);
                if (preq.size() > 0)
                    entry.setPrerequisites(preq);

                // get offered by
                begin = text.indexOf("Offered By:");
                end = text.indexOf("Department:");
                if (end < 0)
                    end = text.indexOf("Course Attributes:");
                if (end > 0) {
                    entry.setOfferedBy(text.substring(begin + 12, end - 1));
                }

                // get department
                begin = text.indexOf("Department:");
                if (begin > 0) {
                    end = text.indexOf("Course Attributes:");
                    entry.setDepartment((text.substring(begin + 12, end - 1)));
                }

                // get campus
                begin = text.indexOf("May be offered at any of the following campuses:");
                String campuses;
                end = text.indexOf("Repeatable for Additional Credit:");
                if (end < 0)
                    end = text.indexOf("Learning Objectives:");
                if (end < 0)
                    end = text.indexOf("Restrictions:");
                if (end < 0)
                    end = text.indexOf("Corequisites:");
                if (end < 0)
                    end = text.indexOf("Prerequisites:");
                if (end < 0) {
                    campuses = text
                            .substring(begin + "May be offered at any of the following campuses:".length() + 5);
                } else {
                    campuses = text.substring(
                            begin + "May be offered at any of the following campuses:".length() + 5, end - 1);
                }
                temp = campuses.replace("    ", "#").split("#");
                List<String> camps = new ArrayList<String>();
                for (String s : temp) {
                    if (s.length() > 1) {
                        camps.add(s);
                    }

                }
                entry.setCampuses(camps);

                // get restrictions
                begin = text.indexOf("Restrictions:");
                end = text.indexOf("Corequisites:");
                if (end < 0)
                    end = text.indexOf("Prerequisites:");
                if (begin > 0 && end < 0) {
                    entry.setRestrictions(
                            text.substring(begin + "Restrictions:".length()).replace("      ", "\n"));
                } else if (begin > 0) {
                    entry.setRestrictions(
                            text.substring(begin + "Restrictions:".length(), end).replace("      ", "\n"));
                }

            } catch (StringIndexOutOfBoundsException e) {
                // no type, not available
                // System.out.println("-----------");
                // System.out.println("Error for cnbr = " + cnbr);
                // System.out.println("-----------");
            }
        } else {
            throw new CourseNotFoundException();
        }

        return entry;
    }

    /**
     * This class contains information return by CatalogDetail.
     * 
     * @author Rendong Chen (ryan), Kaiwen Xu (kevin)
     */
    @SuppressWarnings("unused")
    public class CatalogDetailEntry {
        private Subject searchSubject;
        private int searchCnbr;

        public CatalogDetailEntry(Subject subject, int cnbr) {
            this.searchSubject = subject;
            this.searchCnbr = cnbr;
            this.cnbr = cnbr;
            this.subject = subject;
            name = null;
            description = null;
            levels = null;
            type = null;
            offeredBy = null;
            department = null;
            campuses = null;
            restrictions = null;
            prerequisites = null;

        }

        private Subject subject;
        private int cnbr;
        private String name;
        private String description;
        private List<String> levels;
        private List<Type> type;
        private String offeredBy;
        private String department;
        private List<String> campuses;
        private String restrictions;
        private List<String> prerequisites;

        @Override
        public String toString() {
            StringBuffer myStr = new StringBuffer();
            myStr.append("Subject: " + subject.toString() + "\n");
            myStr.append("CNBR: " + cnbr + "\n");
            if (name != null)
                myStr.append("Name: " + name + "\n");
            if (description != null)
                myStr.append("Description: " + description + "\n");
            if (levels != null) {
                myStr.append("Level: ");
                for (String s : levels)
                    myStr.append(s + " ; ");
                myStr.append("\n");
            }
            if (type != null) {
                myStr.append("Type: ");
                for (Type t : type)
                    myStr.append(t.toString() + " ; ");
                myStr.append("\n");
            }
            if (offeredBy != null)
                myStr.append("OfferedBy: " + offeredBy + "\n");
            if (department != null)
                myStr.append("Department: " + department + "\n");
            if (campuses != null) {
                myStr.append("Campuses: ");
                for (String s : campuses)
                    myStr.append(s + " ; ");
                myStr.append("\n");
            }
            if (restrictions != null)
                myStr.append("Restrictions: " + restrictions + "\n");
            if (prerequisites != null) {
                myStr.append("Prerequisites: ");
                for (String s : prerequisites)
                    myStr.append(s + " ; ");
                myStr.append("\n");
            }
            return myStr.toString();
        }

        private Subject getSearchSubject() {
            return searchSubject;
        }

        private int getSearchCnbr() {
            return searchCnbr;
        }

        public Subject getSubject() {
            return subject;
        }

        public int getCnbr() {
            return cnbr;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public List<String> getLevels() {
            return levels;
        }

        public void setLevels(List<String> levels) {
            this.levels = levels;
        }

        public List<Type> getType() {
            return type;
        }

        public void setType(List<Type> type) {
            this.type = type;
        }

        public String getOfferedBy() {
            return offeredBy;
        }

        public void setOfferedBy(String offeredBy) {
            this.offeredBy = offeredBy;
        }

        public String getDepartment() {
            return department;
        }

        public void setDepartment(String department) {
            this.department = department;
        }

        public List<String> getCampuses() {
            return campuses;
        }

        public void setCampuses(List<String> campuses) {
            this.campuses = campuses;
        }

        public String getRestrictions() {
            return restrictions;
        }

        public void setRestrictions(String restrictions) {
            this.restrictions = restrictions;
        }

        public List<String> getPrerequisites() {
            return prerequisites;
        }

        public void setPrerequisites(List<String> prerequisites) {
            this.prerequisites = prerequisites;
        }

    }

}