From 71c75b65e9dffc820ac994bc598b74fe9cc31f8c Mon Sep 17 00:00:00 2001 From: Modernization Agent Date: Fri, 20 Mar 2026 17:21:54 +0000 Subject: [PATCH] Add Java 17 email slicer with Maven build, core parsing, CLI, and tests Migrate the Python email slicer to Java 17 with standard Maven layout, Maven Wrapper, EmailParts record, EmailSlicer parser, Messages constants, Main CLI entry point, and JUnit 5 test suite (8 tests). --- .../.mvn/wrapper/maven-wrapper.properties | 2 + emailslicer-dkasargod-java/mvnw | 71 +++++++++++++++++++ emailslicer-dkasargod-java/mvnw.cmd | 37 ++++++++++ emailslicer-dkasargod-java/pom.xml | 62 ++++++++++++++++ .../main/java/com/emailslicer/EmailParts.java | 10 +++ .../java/com/emailslicer/EmailSlicer.java | 55 ++++++++++++++ .../src/main/java/com/emailslicer/Main.java | 34 +++++++++ .../main/java/com/emailslicer/Messages.java | 16 +++++ .../java/com/emailslicer/EmailSlicerTest.java | 66 +++++++++++++++++ 9 files changed, 353 insertions(+) create mode 100644 emailslicer-dkasargod-java/.mvn/wrapper/maven-wrapper.properties create mode 100755 emailslicer-dkasargod-java/mvnw create mode 100644 emailslicer-dkasargod-java/mvnw.cmd create mode 100644 emailslicer-dkasargod-java/pom.xml create mode 100644 emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailParts.java create mode 100644 emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailSlicer.java create mode 100644 emailslicer-dkasargod-java/src/main/java/com/emailslicer/Main.java create mode 100644 emailslicer-dkasargod-java/src/main/java/com/emailslicer/Messages.java create mode 100644 emailslicer-dkasargod-java/src/test/java/com/emailslicer/EmailSlicerTest.java diff --git a/emailslicer-dkasargod-java/.mvn/wrapper/maven-wrapper.properties b/emailslicer-dkasargod-java/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..e70e7bc --- /dev/null +++ b/emailslicer-dkasargod-java/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/emailslicer-dkasargod-java/mvnw b/emailslicer-dkasargod-java/mvnw new file mode 100755 index 0000000..2f4b09c --- /dev/null +++ b/emailslicer-dkasargod-java/mvnw @@ -0,0 +1,71 @@ +#!/bin/sh +# Maven Wrapper script — downloads Maven if not already cached, then runs it. +# Based on https://github.com/apache/maven-wrapper + +set -e + +# Determine the project base directory +if [ -z "$MAVEN_PROJECTBASEDIR" ]; then + MAVEN_PROJECTBASEDIR=$(cd "$(dirname "$0")" && pwd) + export MAVEN_PROJECTBASEDIR +fi + +WRAPPER_PROPERTIES="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties" + +if [ ! -f "$WRAPPER_PROPERTIES" ]; then + echo "Error: Could not find $WRAPPER_PROPERTIES" >&2 + exit 1 +fi + +# Read distributionUrl from properties file +distributionUrl=$(grep 'distributionUrl' "$WRAPPER_PROPERTIES" | cut -d'=' -f2- | tr -d '[:space:]') + +if [ -z "$distributionUrl" ]; then + echo "Error: Could not read distributionUrl from $WRAPPER_PROPERTIES" >&2 + exit 1 +fi + +# Set up Maven home in user's local cache +MAVEN_USER_HOME="${MAVEN_USER_HOME:-$HOME/.m2}" +WRAPPER_DIR="$MAVEN_USER_HOME/wrapper/dists" + +# Extract Maven version from URL for directory naming +DIST_NAME=$(basename "$distributionUrl" .zip) +# The zip may contain a directory without the '-bin' suffix +MAVEN_DIR_NAME=$(echo "$DIST_NAME" | sed 's/-bin$//') +MAVEN_HOME="$WRAPPER_DIR/$MAVEN_DIR_NAME" +MAVEN_CMD="$MAVEN_HOME/bin/mvn" + +if [ ! -x "$MAVEN_CMD" ]; then + echo "Downloading Maven from $distributionUrl ..." + mkdir -p "$WRAPPER_DIR" + DOWNLOAD_FILE="$WRAPPER_DIR/$DIST_NAME.zip" + + if command -v curl > /dev/null 2>&1; then + curl -fsSL -o "$DOWNLOAD_FILE" "$distributionUrl" + elif command -v wget > /dev/null 2>&1; then + wget -q -O "$DOWNLOAD_FILE" "$distributionUrl" + else + echo "Error: Neither curl nor wget found. Cannot download Maven." >&2 + exit 1 + fi + + echo "Extracting Maven ..." + if command -v unzip > /dev/null 2>&1; then + unzip -q -o "$DOWNLOAD_FILE" -d "$WRAPPER_DIR" + elif command -v jar > /dev/null 2>&1; then + mkdir -p "$MAVEN_HOME" + cd "$WRAPPER_DIR" + jar xf "$DOWNLOAD_FILE" + cd "$MAVEN_PROJECTBASEDIR" + elif command -v python3 > /dev/null 2>&1; then + python3 -c "import zipfile,sys; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])" "$DOWNLOAD_FILE" "$WRAPPER_DIR" + else + echo "Error: No tool found to extract zip (tried unzip, jar, python3)." >&2 + exit 1 + fi + rm -f "$DOWNLOAD_FILE" + chmod +x "$MAVEN_CMD" +fi + +exec "$MAVEN_CMD" "$@" diff --git a/emailslicer-dkasargod-java/mvnw.cmd b/emailslicer-dkasargod-java/mvnw.cmd new file mode 100644 index 0000000..494f3f5 --- /dev/null +++ b/emailslicer-dkasargod-java/mvnw.cmd @@ -0,0 +1,37 @@ +@REM Maven Wrapper script for Windows +@REM Based on https://github.com/apache/maven-wrapper + +@echo off +setlocal + +set "MAVEN_PROJECTBASEDIR=%~dp0" +set "WRAPPER_PROPERTIES=%MAVEN_PROJECTBASEDIR%.mvn\wrapper\maven-wrapper.properties" + +if not exist "%WRAPPER_PROPERTIES%" ( + echo Error: Could not find %WRAPPER_PROPERTIES% >&2 + exit /b 1 +) + +for /f "tokens=1,* delims==" %%a in ('findstr "distributionUrl" "%WRAPPER_PROPERTIES%"') do set "distributionUrl=%%b" + +if "%distributionUrl%"=="" ( + echo Error: Could not read distributionUrl >&2 + exit /b 1 +) + +set "MAVEN_USER_HOME=%USERPROFILE%\.m2" +set "WRAPPER_DIR=%MAVEN_USER_HOME%\wrapper\dists" + +for %%i in ("%distributionUrl%") do set "DIST_NAME=%%~ni" +set "MAVEN_HOME=%WRAPPER_DIR%\%DIST_NAME%" +set "MAVEN_CMD=%MAVEN_HOME%\bin\mvn.cmd" + +if not exist "%MAVEN_CMD%" ( + echo Downloading Maven from %distributionUrl% ... + mkdir "%WRAPPER_DIR%" 2>nul + powershell -Command "Invoke-WebRequest -Uri '%distributionUrl%' -OutFile '%WRAPPER_DIR%\%DIST_NAME%.zip'" + powershell -Command "Expand-Archive -Path '%WRAPPER_DIR%\%DIST_NAME%.zip' -DestinationPath '%WRAPPER_DIR%' -Force" + del "%WRAPPER_DIR%\%DIST_NAME%.zip" +) + +"%MAVEN_CMD%" %* diff --git a/emailslicer-dkasargod-java/pom.xml b/emailslicer-dkasargod-java/pom.xml new file mode 100644 index 0000000..eeee4c1 --- /dev/null +++ b/emailslicer-dkasargod-java/pom.xml @@ -0,0 +1,62 @@ + + + 4.0.0 + + com.emailslicer + email-slicer + 1.0.0 + jar + + Email Slicer + A CLI tool that parses an email address into its username and domain parts + + + 17 + 17 + UTF-8 + 5.10.2 + + + + + org.junit.jupiter + junit-jupiter + ${junit.version} + test + + + + + email-slicer + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + com.emailslicer.Main + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.12.1 + + 17 + 17 + + + + + diff --git a/emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailParts.java b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailParts.java new file mode 100644 index 0000000..a309d9a --- /dev/null +++ b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailParts.java @@ -0,0 +1,10 @@ +package com.emailslicer; + +/** + * Immutable value object holding the parsed username and domain parts of an email address. + * + * @param username the local part of the email address (before the {@code @} symbol) + * @param domain the domain part of the email address (after the {@code @} symbol) + */ +public record EmailParts(String username, String domain) { +} diff --git a/emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailSlicer.java b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailSlicer.java new file mode 100644 index 0000000..58bb48c --- /dev/null +++ b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/EmailSlicer.java @@ -0,0 +1,55 @@ +package com.emailslicer; + +/** + * Parses an email address string into its username and domain components. + * + *

This class contains the core parsing logic, separated from I/O concerns + * to allow direct unit testing without mocking {@code System.in}/{@code System.out}. + */ +public final class EmailSlicer { + + private EmailSlicer() { + // Utility class — not instantiable + } + + /** + * Parses the given email string into an {@link EmailParts} record. + * + *

The input is trimmed before validation. Validation requires: + *

+ * + * @param email the raw email address string + * @return an {@link EmailParts} instance containing the username and domain + * @throws IllegalArgumentException if the input fails validation + */ + public static EmailParts parse(String email) { + if (email == null || email.isBlank()) { + throw new IllegalArgumentException(Messages.INVALID_EMAIL_MESSAGE); + } + + String trimmed = email.strip(); + + int atIndex = trimmed.indexOf('@'); + if (atIndex == -1) { + throw new IllegalArgumentException(Messages.INVALID_EMAIL_MESSAGE); + } + + // Reject multiple '@' characters + if (trimmed.indexOf('@', atIndex + 1) != -1) { + throw new IllegalArgumentException(Messages.INVALID_EMAIL_MESSAGE); + } + + String username = trimmed.substring(0, atIndex); + String domain = trimmed.substring(atIndex + 1); + + if (username.isEmpty() || domain.isEmpty()) { + throw new IllegalArgumentException(Messages.INVALID_EMAIL_MESSAGE); + } + + return new EmailParts(username, domain); + } +} diff --git a/emailslicer-dkasargod-java/src/main/java/com/emailslicer/Main.java b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/Main.java new file mode 100644 index 0000000..8f057bd --- /dev/null +++ b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/Main.java @@ -0,0 +1,34 @@ +package com.emailslicer; + +import java.util.Scanner; + +/** + * CLI entry point for the Email Slicer application. + * + *

Prompts the user for an email address, delegates parsing to + * {@link EmailSlicer#parse(String)}, and prints the result. Exits with + * code 1 when the input is invalid. + */ +public final class Main { + + private Main() { + // Entry-point class — not instantiable + } + + public static void main(String[] args) { + System.out.println(Messages.PROMPT_MESSAGE); + + try (Scanner scanner = new Scanner(System.in)) { + String email = scanner.nextLine().strip(); + + try { + EmailParts parts = EmailSlicer.parse(email); + System.out.println(Messages.USERNAME_PREFIX + parts.username()); + System.out.println(Messages.DOMAIN_PREFIX + parts.domain()); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + System.exit(1); + } + } + } +} diff --git a/emailslicer-dkasargod-java/src/main/java/com/emailslicer/Messages.java b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/Messages.java new file mode 100644 index 0000000..66b5793 --- /dev/null +++ b/emailslicer-dkasargod-java/src/main/java/com/emailslicer/Messages.java @@ -0,0 +1,16 @@ +package com.emailslicer; + +/** + * Centralised store for user-facing messages. + */ +public final class Messages { + + public static final String PROMPT_MESSAGE = "Please enter your Email Id:"; + public static final String INVALID_EMAIL_MESSAGE = "Please enter a valid Email Id."; + public static final String USERNAME_PREFIX = "Your username is: "; + public static final String DOMAIN_PREFIX = "Your domain is: "; + + private Messages() { + // Utility class — not instantiable + } +} diff --git a/emailslicer-dkasargod-java/src/test/java/com/emailslicer/EmailSlicerTest.java b/emailslicer-dkasargod-java/src/test/java/com/emailslicer/EmailSlicerTest.java new file mode 100644 index 0000000..14de000 --- /dev/null +++ b/emailslicer-dkasargod-java/src/test/java/com/emailslicer/EmailSlicerTest.java @@ -0,0 +1,66 @@ +package com.emailslicer; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Unit tests for {@link EmailSlicer#parse(String)}. + */ +class EmailSlicerTest { + + @Test + @DisplayName("Valid email is split into username and domain") + void validEmail() { + EmailParts result = EmailSlicer.parse("avimax37@gmail.com"); + assertEquals(new EmailParts("avimax37", "gmail.com"), result); + } + + @Test + @DisplayName("Leading and trailing whitespace is trimmed before parsing") + void leadingTrailingWhitespace() { + EmailParts result = EmailSlicer.parse(" user@example.org "); + assertEquals(new EmailParts("user", "example.org"), result); + } + + @Test + @DisplayName("Missing '@' throws IllegalArgumentException") + void missingAtSign() { + IllegalArgumentException ex = assertThrows( + IllegalArgumentException.class, + () -> EmailSlicer.parse("invalidemail") + ); + assertEquals(Messages.INVALID_EMAIL_MESSAGE, ex.getMessage()); + } + + @Test + @DisplayName("Empty string throws IllegalArgumentException") + void emptyString() { + assertThrows(IllegalArgumentException.class, () -> EmailSlicer.parse("")); + } + + @Test + @DisplayName("Null input throws IllegalArgumentException") + void nullInput() { + assertThrows(IllegalArgumentException.class, () -> EmailSlicer.parse(null)); + } + + @Test + @DisplayName("Multiple '@' signs throws IllegalArgumentException") + void multipleAtSigns() { + assertThrows(IllegalArgumentException.class, () -> EmailSlicer.parse("a@b@c.com")); + } + + @Test + @DisplayName("Empty username (@domain.com) throws IllegalArgumentException") + void emptyUsername() { + assertThrows(IllegalArgumentException.class, () -> EmailSlicer.parse("@domain.com")); + } + + @Test + @DisplayName("Empty domain (user@) throws IllegalArgumentException") + void emptyDomain() { + assertThrows(IllegalArgumentException.class, () -> EmailSlicer.parse("user@")); + } +}