Download and print a CSV report based on user input

Posted on

Problem

I’m learning Java and I did one exercise that consists in reading the input of the user (name of the network and date of the report) and return the csv that was inputed by the user. I know that the code is far from clean but I dont know how to make it cleaner and is so far working. So I basically need help and suggestions on how to write a cleaner code.



import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Objects;
import java.util.Scanner;
import java.io.*;
import java.net.*;

public class App {

    public static void main(String[] args) throws Exception {
        Scanner input = new Scanner(System.in);
        System.out.println("Choose the network between supernetwork or adumbrella");
        System.out.print("Selection: ");
        String userInput = input.nextLine();

        String date = "";
        if (userInput.equals("supernetwork")) {
            System.out.println("Choose the month and date on the MM-DD format");
            System.out.print("Date: ");
            date = input.nextLine();
        }
        if (date.equals("09-15")) {
            URL adnetwork = new URL("/expertise-test/supernetwork/report/daily/2017-09-15.csv");

            URLConnection yc = adnetwork.openConnection();

            BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));

            String inputLine;
            try {
                System.out.println("Daily Report");

            } catch (Exception e) {
                System.out.println(e);
            }

            while ((inputLine = in.readLine()) != null)
                System.out.println(inputLine);
            in.close();
        } else if (date.equals("09-16")) {
            URL adnetwork = new URL("expertise-test/supernetwork/report/daily/2017-09-16.csv");

            URLConnection yc = adnetwork.openConnection();

            BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));

            String inputLine;
            try {
                System.out.println("daily_report");

            } catch (Exception e) {
                System.out.println(e);
            }

            while ((inputLine = in.readLine()) != null)
                System.out.println(inputLine);
            in.close();

        } else if (userInput.equals("adumbrella")){
            System.out.println("Choose the month and date on the MM-DD format");
            System.out.print("Date: ");
            date = input.nextLine();
             if(date.equals("09-15")) {
                URL adnetwork = new URL("expertise-test/reporting/adumbrella/adumbrella-15_9_2017.csv");

                URLConnection yc = adnetwork.openConnection();

                BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));

                String inputLine;
                try {
                    System.out.println("Daily Report");

                } catch (Exception e) {
                    System.out.println(e);
                }

                while ((inputLine = in.readLine()) != null)
                    System.out.println(inputLine);
                in.close();
            } else if (date.equals("09-16")) {
                URL adnetwork = new URL("/expertise-test/reporting/adumbrella/adumbrella-16_9_2017.csv");

                URLConnection yc = adnetwork.openConnection();

                BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));

                String inputLine;
                try {
                    System.out.println("daily_report");

                } catch (Exception e) {
                    System.out.println(e);
                }

                while ((inputLine = in.readLine()) != null)
                    System.out.println(inputLine);
                in.close();
        }
    }
}}





Solution

You have a significant bug. This code:

    if (userInput.equals("supernetwork")) {
        System.out.println("Choose the month and date on the MM-DD format");
        System.out.print("Date: ");
        date = input.nextLine();
    }
    if (date.equals("09-15")) {

will evaluate the second if for supernetwork even if it shouldn’t. The second if is at the wrong nesting level and needs to be contained within the block of the first if.

Consider, as a user convenience, only paying attention to the first letter of the input string to choose which network you’re downloading from. This can then be used as a key into a map.

Your date input code is strange. You force the year to be 2017, which is I guess fine? But you don’t tell the user that you’re doing this, nor do you tell the user that you’re only going to be paying attention to two dates: 09-15 or 09-16. This is a guessing game that I would not want to play if I were a user treating this application as a black box. Instead, tell the user that the year will be set as 2017, and simply have them input the month and day. Then, do not if() on the date; just format it into your URL. Worst case, they provide a date for which the URL will 404 at them. If you have an exhaustive list of dates that you know are present on the server with nothing else, an alternative implementation could validate the date input against these dates before sending off the HTTP request; but I consider this unlikely.

You repeat the download code (four times!) Don’t do this. Just write it once and properly parametrise your URL.

There’s not really a point to reading the connection response line-by-line. You can just transferTo in one shot, and have the HTTP stream copied to the stdout stream. Be sure to wrap the HTTP stream in a try-with-resources.

For me to test this out, I had to fill in a real hostname; I’m using httpbin.org which sends you test responses for any URL.

Consider capturing what’s different between the two networks in a Network class – namely, the URL and its date format – and then selecting an instance via map.

Suggested

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.lang.System.out;

public class App {

    private static class Network {
        private static final URL BASE;

        static {
            try {
                BASE = new URL("https://httpbin.org/anything/expertise-test/");
            } catch (MalformedURLException e) { throw new RuntimeException(e); }
        }

        private static final Network
            supernetwork = new Network("supernetwork", "yyyy-MM-dd",
                "supernetwork/report/daily/%s.csv"),
            adumbrella = new Network("adumbrella", "d_M_y",
                "reporting/adumbrella/adumbrella-%s.csv");
        private static final Map<Character, Network> networks = Map.of(
            supernetwork.getSelector(), supernetwork,
            adumbrella.getSelector(), adumbrella
        );

        private final DateFormat dateFormat;
        private final String urlFormat;
        public final String name;

        protected Network(String name, String dateFormat, String urlFormat) {
            this.dateFormat = new SimpleDateFormat(dateFormat);
            this.urlFormat = urlFormat;
            this.name = name;
        }

        public static Network fromSelection(Scanner input) {
            String prompt = String.format(
                "Choose the network, %s or %s: ", supernetwork.getPrompt(), adumbrella.getPrompt()
            );
            while (true) {
                out.print(prompt);
                String line = input.nextLine();
                if (line.length() > 0) {
                    char userInput = Character.toLowerCase(line.charAt(0));
                    Network network = networks.get(userInput);
                    if (network != null) return network;
                }
                out.println("Invalid input");
            }
        }

        public String getPrompt() {
            return String.format("(%c)%s", getSelector(), name.substring(1));
        }

        public Character getSelector() { return name.charAt(0); }

        public URL makeURL(Date date) throws MalformedURLException {
            String file = String.format(urlFormat, dateFormat.format(date));
            return new URL(BASE, file);
        }

        public void downloadTo(Date date, OutputStream output) throws IOException {
            URL url = makeURL(date);
            URLConnection yc = url.openConnection();
            try (InputStream stream = yc.getInputStream()) {
                stream.transferTo(output);
            }
        }

        public void downloadAndPrint(Date date) throws IOException { downloadTo(date, out); }
    }

    private static final int YEAR = 2017;
    private static final SimpleDateFormat inputFormat = new SimpleDateFormat("MM-dd");

    private static Date inputDate(Scanner input) {
        Calendar cal = Calendar.getInstance();
        String prompt = String.format("Choose the month and day in the %s format (within %d): ", inputFormat.toPattern(), YEAR);
        while (true) {
            out.print(prompt);
            try {
                cal.setTime(inputFormat.parse(input.nextLine()));
                break;
            } catch (ParseException e) {
                out.println(e.getMessage());
            }
        }
        cal.set(Calendar.YEAR, YEAR);
        return cal.getTime();
    }

    public static void main(String[] args) throws IOException {
        Scanner input = new Scanner(System.in);
        Network network = Network.fromSelection(input);
        Date date = inputDate(input);
        network.downloadAndPrint(date);
    }
}

Output

Choose the network, (s)upernetwork or (a)dumbrella: a
Choose the month and day in the MM-dd format (within 2017): 08-23
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2", 
    "Host": "httpbin.org", 
    "User-Agent": "Java/18.0.1.1", 
    "X-Amzn-Trace-Id": "Root=1-62c1f812-551eec09456359ce72981bea"
  }, 
  "json": null, 
  "method": "GET", 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "https://httpbin.org/anything/expertise-test/reporting/adumbrella/adumbrella-23_8_2017.csv"
}

Leave a Reply

Your email address will not be published. Required fields are marked *