├── .dockerignore ├── Thumbnail.jpeg ├── .gitignore ├── jbang-catalog.json ├── docker-compose.yaml ├── .satori.yml ├── Dockerfile ├── src ├── main │ └── java │ │ └── it │ │ └── nanowar │ │ └── ofsteel │ │ └── helloworld │ │ ├── HelloWorldMainLauncherClass.java │ │ └── HelloWorldServlet.java └── test │ └── java │ └── it │ └── nanowar │ └── ofsteel │ └── helloworld │ └── HelloWorldMainLauncherClassTest.java ├── .github └── workflows │ └── hello-world-ci.yml ├── pom.xml └── README.md /.dockerignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .git 3 | -------------------------------------------------------------------------------- /Thumbnail.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NanowarOfSteel/HelloWorld/HEAD/Thumbnail.jpeg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Maven result files 2 | target/ 3 | *.falsemetal 4 | *.joeydecaio 5 | .idea 6 | .vscode 7 | -------------------------------------------------------------------------------- /jbang-catalog.json: -------------------------------------------------------------------------------- 1 | { 2 | "catalogs": {}, 3 | "aliases": { 4 | "helloworld": { 5 | "script-ref": "src/main/java/it/nanowar/ofsteel/helloworld/HelloWorldMainLauncherClass.java", 6 | "java-agents": [] 7 | } 8 | }, 9 | "templates": {} 10 | } -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | app: # Service name 3 | build: 4 | context: . # Dockerfile directory relative path from this file 5 | dockerfile: Dockerfile # Dockerfile file name 6 | ports: 7 | - "8080:8080" # First port is the local port of your machine where the program execution will be binded -------------------------------------------------------------------------------- /.satori.yml: -------------------------------------------------------------------------------- 1 | settings: 2 | name: HelloWorld.java 3 | author: 4 | - https://github.com/NanowarOfSteel 5 | image: maven:3.8.8-eclipse-temurin-17 6 | 7 | install: 8 | assertReturnCode: 0 9 | clone: 10 | - git clone --depth 1 https://github.com/NanowarOfSteel/HelloWorld.git 11 | compile: 12 | - cd HelloWorld/src/main/java/it/nanowar/ofsteel/helloworld; javac HelloWorldMainLauncherClass.java 13 | 14 | helloworld: 15 | assertReturnCode: 1 16 | assertStdoutContains: 17 | - Hello World Programmer Start 18 | - Hello World! 19 | - Program Finished! 20 | assertStderrContains: NullPointerException 21 | run: 22 | - cd HelloWorld/src/main/java; java it.nanowar.ofsteel.helloworld.HelloWorldMainLauncherClass 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Step 1: Use an official Maven image to build the project 2 | FROM docker.io/maven:3.9.9-eclipse-temurin-21 AS build 3 | 4 | # Step 2: Set the working directory inside the container 5 | WORKDIR /app 6 | 7 | # Step 3: Copy the project files into the container 8 | COPY . . 9 | 10 | # Step 4: Build the project using Maven to create a WAR file 11 | RUN mvn clean package 12 | 13 | # Step 5: Use Tomcat image to deploy the WAR 14 | FROM docker.io/tomcat:jdk21 15 | 16 | # Step 6: Set the working directory inside the Tomcat container 17 | WORKDIR /usr/local/tomcat/webapps 18 | 19 | # Step 7: Copy the built WAR file from the Maven build stage into Tomcat's webapps folder 20 | COPY --from=build /app/target/nano.war /usr/local/tomcat/webapps/ROOT.war 21 | 22 | # Step 8: Expose the port that Tomcat listens on 23 | EXPOSE 8080 24 | 25 | # Step 9: Set the command to run Tomcat 26 | CMD ["catalina.sh", "run"] 27 | -------------------------------------------------------------------------------- /src/main/java/it/nanowar/ofsteel/helloworld/HelloWorldMainLauncherClass.java: -------------------------------------------------------------------------------- 1 | package it.nanowar.ofsteel.helloworld; 2 | 3 | public class HelloWorldMainLauncherClass { 4 | 5 | public HelloWorldMainLauncherClass(int foo) { 6 | 7 | super(); 8 | this.foo=foo; 9 | } 10 | 11 | private Integer foo=0; 12 | 13 | public void songRefrain() { 14 | 15 | for (int i=0; i"); 25 | try { 26 | HelloWorldMainLauncherClass.main(new String[0]); 27 | } catch (Exception e) { 28 | // Stack traces in production? Not ideal for security... but with Giorgio Mastrota's power, we're safe! 29 | e.printStackTrace(); 30 | } finally { 31 | System.setOut(new PrintStream(System.out)); 32 | System.setErr(new PrintStream(System.err)); 33 | } 34 | String capturedOutput = baos.toString(); 35 | out.println("
" + capturedOutput + "
"); 36 | out.println(""); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/it/nanowar/ofsteel/helloworld/HelloWorldMainLauncherClassTest.java: -------------------------------------------------------------------------------- 1 | package it.nanowar.ofsteel.helloworld; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.PrintStream; 7 | 8 | import static org.junit.jupiter.api.Assertions.*; 9 | 10 | class HelloWorldMainLauncherClassTest { 11 | @Test 12 | void testConstructorInitialization() { 13 | HelloWorldMainLauncherClass instance = new HelloWorldMainLauncherClass(5); 14 | assertNotNull(instance, "Instance should be created"); 15 | } 16 | 17 | @Test 18 | void testSongRefrainOutput() { 19 | // Configure 20 | int expectRuns = 2; 21 | int expectOutputs = expectRuns * 2; // each run does 2 outputs 22 | 23 | HelloWorldMainLauncherClass instance = new HelloWorldMainLauncherClass(expectRuns); 24 | 25 | // Catch the output 26 | ByteArrayOutputStream outContent = new ByteArrayOutputStream(); 27 | System.setOut(new PrintStream(outContent)); 28 | 29 | // Do test 30 | instance.songRefrain(); 31 | 32 | // Check the number of outputs 33 | String output = outContent.toString(); 34 | long helloWorldCount = output.lines().filter(line -> line.equals("Hello World!")).count(); 35 | assertEquals(expectOutputs, helloWorldCount, String.format( "The songRefrain method should print 'Hello World!' %d times", expectOutputs)); 36 | } 37 | 38 | @Test 39 | void testFalseMethodThrowsNullPointerException() { 40 | HelloWorldMainLauncherClass instance = new HelloWorldMainLauncherClass(1); 41 | 42 | // Make sure the NPE is thrown 43 | assertThrows(NullPointerException.class, instance::falseMethod, "falseMethod should throw a NullPointerException"); 44 | } 45 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | it.nanowar.ofsteel.helloworld 4 | HelloWorld 5 | 0.0.1-SNAPSHOT 6 | 7 | 21 8 | 21 9 | UTF-8 10 | 11 | war 12 | 13 | nano 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-jar-plugin 19 | 3.1.0 20 | 21 | 22 | 23 | true 24 | lib/ 25 | it.nanowar.ofsteel.helloworld.HelloWorldMainLauncherClass 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | jakarta.servlet 35 | jakarta.servlet-api 36 | 5.0.0 37 | provided 38 | 39 | 40 | org.junit.jupiter 41 | junit-jupiter 42 | 5.11.3 43 | test 44 | 45 | 46 | io.parsingdata 47 | metal-core 48 | 10.0.0 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HelloWorld.java 2 | 3 | ![thumbnail](./Thumbnail.jpeg) 4 | 5 | Welcome to the **Nanowar Of Steel**'s first GitHub project, and first ever example of a **source-code song**. 6 | The aim of this project is to support and enforce "_True metal programming_", that basically means: "_write code so badly that only you can sing it_". 7 | 8 | You can find the source-code video in the link below: 9 | https://www.youtube.com/watch?v=yup8gIXxWDU 10 | 11 | [Here](https://nanowar.it/) is the Nanowar Of Steel official website. 12 | 13 | [Here](https://www.youtube.com/@nanowarVEVO) is the Nanowar Of Steel Youtube Channel. 14 | 15 | Some important notes: 16 | 1. Beware of ```Joey De Caio```, if set to null it may suddenly cancel the program execution with a NullPointerException. 17 | 2. ```metal``` variable is very important! If it is set to "false", it may trigger the Joey De Caio variable mentioned above. 18 | 3. ```tizio``` and ```foo``` are very close friends. 19 | 4. ```pippo``` isn't ```tizio```'s friend, but he's been flirting with ```foo```. 20 | 5. In the comments "**manage**" should be renamed as "**handle**" (we all wish "manage" was the right word, but it's not). 21 | 6. The constructor argument is used to control the number of executions. However, it may be completely useless if the execution is cancelled by ```Joey De Caio```. 22 | 7. "_Write once, run anywhere_" means literally anywhere (e.g. Hellfest). 23 | 8. ```songRefrain()``` identifies itself as a void method. 24 | 25 | Below you will find a super detailed guide to the program, of course written with ChatGPT. 26 | 27 | --- 28 | 29 | # HelloWorldMainLauncherClass 30 | 31 | This project contains a simple Java application that demonstrates the basic usage of loops, conditionals, and handling null-pointer exceptions. The main functionality includes printing "Hello World!" multiple times based on a user-defined parameter and intentionally introducing a bug to highlight error handling. 32 | 33 | ## Overview 34 | 35 | The `HelloWorldMainLauncherClass` performs the following tasks: 36 | 37 | 1. **Initialization**: Accepts an integer parameter (`foo`) that controls how many times "Hello World!" will be printed. 38 | 2. **Song Refrain**: Prints "Hello World!" twice—first using a `for` loop and then using a `while` loop. 39 | 3. **Exception Handling**: Contains a method `falseMethod()` that introduces a `NullPointerException` by calling `length()` on a `null` string to simulate error handling. 40 | 41 | ## Features 42 | 43 | - **Hello World printing**: Outputs the message "Hello World!" a number of times based on the provided parameter. 44 | - **Loops**: Demonstrates basic usage of `for` and `while` loops in Java. 45 | - **Exception simulation**: Introduces a `NullPointerException` for demonstration purposes. 46 | - **Basic Java structure**: Showcases constructor usage, instance variables, and method definitions. 47 | 48 | ## Prerequisites 49 | 50 | - Java Development Kit (JDK) 21 or higher. 51 | - A Java IDE (like IntelliJ IDEA, Eclipse, or NetBeans) or a command-line environment to compile and run the Java program. 52 | 53 | ## Installation 54 | 55 | To set up and run this project locally, follow these steps: 56 | 57 | 1. Clone the repository: 58 | 59 | ```bash 60 | git clone https://github.com/NanowarOfSteel/HelloWorld.git 61 | ``` 62 | 63 | 2. Navigate into the project sources directory: 64 | 65 | ```bash 66 | cd HelloWorld 67 | ``` 68 | 69 | 3. Compile and run the Java file: 70 | 71 | ```bash 72 | java src/main/java/it/nanowar/ofsteel/helloworld/HelloWorldMainLauncherClass.java 73 | ``` 74 | 75 | ## Usage 76 | 77 | Once you run the program, you will see the following output: 78 | 79 | ```text 80 | Hello World Programmer Start 81 | Hello World! 82 | Hello World! 83 | Hello World! 84 | Hello World! 85 | Program Finished! 86 | Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "joeyDeCaio" is null 87 | at HelloWorldMainLauncherClass.falseMethod(HelloWorldMainLauncherClass.java:35) 88 | at HelloWorldMainLauncherClass.main(HelloWorldMainLauncherClass.java:27) 89 | ``` 90 | 91 | ### Configuration 92 | 93 | The number of times "Hello World!" is printed can be controlled by changing the parameter passed to the constructor of `HelloWorldMainLauncherClass`. For example: 94 | 95 | ```java 96 | HelloWorldMainLauncherClass tizio = new HelloWorldMainLauncherClass(3); 97 | ``` 98 | 99 | This will print "Hello World!" six times. 100 | 101 | ## Code Explanation 102 | 103 | 1. **Constructor**: The constructor takes an integer `foo` that determines how many times the message will be printed. 104 | ```java 105 | public HelloWorldMainLauncherClass(int foo) { 106 | super(); 107 | this.foo = foo; 108 | } 109 | ``` 110 | 111 | 2. **songRefrain() Method**: The method contains two loops—`for` and `while`—both of which print "Hello World!" the number of times specified by `foo`. 112 | ```java 113 | public void songRefrain() { 114 | for (int i = 0; i < foo; i++) { 115 | System.out.println("Hello World!"); 116 | } 117 | 118 | int pippo = 0; 119 | while (pippo < foo) { 120 | System.out.println("Hello World!"); 121 | pippo++; 122 | } 123 | } 124 | ``` 125 | 126 | 3. **falseMethod() Method**: This method deliberately introduces a bug by attempting to call `length()` on a `null` string. 127 | ```java 128 | public void falseMethod() { 129 | boolean metal = false; 130 | if (metal == false) { 131 | String joeyDeCaio = null; 132 | joeyDeCaio.length(); 133 | } 134 | } 135 | ``` 136 | ### Notes: 137 | 138 | - **Bug introduction**: The purpose of `falseMethod()` is to demonstrate a scenario where an exception is thrown. The `NullPointerException` is handled by the JVM, but no explicit exception handling is implemented in this case. 139 | 140 | - **Extending the Program**: You can extend the program by adding more features like exception handling, more complex message outputs, or additional loops and conditionals. 141 | 142 | # JBang Guide 143 | 144 | This repository contains a jbang catalog that allows you to run the HelloWorld program with the command `jbang hello@nanowarofsteel/hello`. 145 | 146 | ## Table of Contents 147 | - [Prerequisites](#jbang-prerequisites) 148 | - [Usage](#jbang-usage) 149 | 150 | ## JBang Prerequisites 151 | 152 | To use the jbang catalog, you need to have jbang installed. You can install jbang [here](https://www.jbang.dev/download/). 153 | 154 | ## JBang Usage 155 | 156 | To run the HelloWorld program with `jbang`, you can use the following command directly without cloning the repository: 157 | 158 | ```bash 159 | jbang hello@nanowarofsteel/HelloWorld 160 | ``` 161 | 162 | If you have cloned the repository, you can run the program with the following command: 163 | 164 | ```bash 165 | jbang hello 166 | ``` 167 | 168 | # Docker Guide 169 | 170 | This repository contains a Dockerfile that automates the process of building and running a Java application using Maven. The Docker image is built in two stages: the first stage builds the application with Maven, and the second stage runs the application with a minimal OpenJDK 17 image. 171 | 172 | ## Table of Contents 173 | - [Prerequisites](#prerequisites) 174 | - [Build and Run Instructions](#build-and-run-instructions) 175 | - [Usage](#usage) 176 | - [Cleaning Up](#cleaning-up) 177 | - [Notes](#notes) 178 | - [Performance considerations](#performance-considerations) 179 | 180 | ## Prerequisites 181 | 182 | Before building and running the Docker image, make sure you have the following installed: 183 | 184 | - **Docker**: [Install Docker](https://www.docker.com/get-started) 185 | - **Maven**: (Optional) Maven is only needed locally for building the project if you're not using the Docker build. 186 | 187 | ## Build and Run Instructions 188 | 189 | ### 1. Clone the repository 190 | 191 | First, clone the repository containing the project and the Dockerfile to your local machine: 192 | 193 | ```bash 194 | git clone https://github.com/NanowarOfSteel/HelloWorld.git 195 | cd HelloWorld 196 | ``` 197 | 198 | ### 2. Build the Docker image 199 | 200 | You can build the Docker image using the following command. Make sure you're 201 | in the root directory of the project, then point out the location of the 202 | Dockerfile with the `-f` option: 203 | 204 | ```bash 205 | docker build -t my-java-app . 206 | ``` 207 | 208 | This command will: 209 | 210 | 1. Use an official Maven image to build the application. 211 | 2. Package the application into a JAR file. 212 | 3. Use a slim OpenJDK 21 image to run the resulting application (**kinda**). 213 | 214 | ## Usage 215 | 216 | After the build is complete, you can run the Docker container using: 217 | 218 | ```bash 219 | docker run --rm my-java-app 220 | ``` 221 | 222 | ## Cleaning Up 223 | 224 | If you didn't use the option `--rm` when instanciating the container, you will 225 | have to manually remove the container and image once you're done: 226 | 227 | ```bash 228 | docker rm # Remove the container 229 | docker rmi my-java-app # Remove the image 230 | ``` 231 | 232 | ## Notes 233 | 234 | - **Multi-stage build**: The Dockerfile uses a multi-stage build to ensure the final image is small and optimized for running the application. The first stage uses the Maven image to build the application, and the second stage uses a slim JDK image to run it. 235 | - **JAR file location**: The final JAR file is copied from the `/target` directory in the Maven build stage to the working directory in the runtime stage (`/app`). 236 | 237 | ## Performance considerations 238 | 239 | In order to achieve better performance experience this code live. 240 | Due to resource allocation issues there are only limited possibilities: 241 | 242 | - FRIDAY 21 FEBRUARY 2025: Vienna, Austria - Simm City 243 | 244 | - SATURDAY 22 FEBRUARY 2025: Leipzig, Germany - Hellraiser 245 | 246 | - SUNDAY 23 FEBRUARY 2025: Stuttgart, Germany - Halle, Im Wizemann 247 | 248 | - MONDAY 24 FEBRUARY 2025: Hamburg, Germany - Kaiserkeller (Grosse Freiheit) 249 | 250 | - WEDNESDAY 26 FEBRUARY 2025: Paris, France - La Machine du Moulin Rouge 251 | 252 | - THURSDAY 27 FEBRUARY 2025: Pratteln, Switzerland - Z7 Konzertfabrik 253 | 254 | - FRIDAY 28 FEBRUARY 2025: Villeurbanne, France - La Rayonne 255 | 256 | - SATURDAY 1 MARCH 2025: Lindau, Germany - Club Vaudeville 257 | 258 | - SUNDAY 2 MARCH 2025: Nuremberg, Germany - HIRSCH 259 | 260 | - TUESDAY 4 MARCH 2025: Aarhus, Denmark - VoxHall 261 | 262 | - WEDNESDAY 5 MARCH 2025: Tilburg, Netherlands - 013 263 | 264 | - THURSDAY 6 MARCH 2025: Frankfurt, Germany - Zoom Frankfurt 265 | 266 | - FRIDAY 7 MARCH 2025: Wrocław, Poland - Transformator 267 | 268 | - SATURDAY 8 MARCH 2025: Budapest, Hungary - Barba Negra 269 | 270 | - SUNDAY 9 MARCH 2025: Krakow, Poland - Kwadrat 271 | 272 | - MONDAY 10 MARCH 2025: Berlin, Germany - Columbia Theater 273 | 274 | - WEDNESDAY 12 MARCH 2025: Antwerp, Belgium - Kavka Zappa 275 | 276 | - THURSDAY 13 MARCH 2025: Bochum, Germany - Matrix 277 | 278 | - FRIDAY 14 MARCH 2025: Drachten, Netherlands - Poppodium Iduna 279 | 280 | - SATURDAY 15 MARCH 2025: Strasbourg, France - Le Molodoï 281 | 282 | - SUNDAY 16 MARCH 2025: Munich, Germany - Backstage 283 | 284 | - FRIDAY 4 - SATURDAY 5 APRIL 2025: epic fest denmark 2025: - Roskilde-Hallerne, Roskilde, Denmark 285 | 286 | Further information about upcoming resources can be found here: https://tour.nanowar.it 287 | 288 | 289 | ## Troubleshooting 290 | 291 | - **Issue**: The application isn't starting or doesn't work as expected. 292 | - **Solution**: Check the logs for any error messages by running: 293 | ```bash 294 | docker logs 295 | ``` 296 | 297 | - **Issue**: Docker build fails due to missing dependencies. 298 | - **Solution**: Make sure all necessary dependencies are listed in your `pom.xml` file, and try running `mvn clean install` locally to check for issues before attempting the Docker build. 299 | 300 | --- 301 | ## Docker compose guide 302 | 303 | ## Prerequisites 304 | 305 | - Docker: [Install Docker](https://www.docker.com/get-started) 306 | - Docker compose: [Install Docker Compose](https://docs.docker.com/compose/install) 307 | 308 | ## Build and Run Instructions 309 | 310 | ### 1. Clone the repository 311 | 312 | Do as described in [Docker Build and Run Instructions](#1-clone-the-repository) 313 | 314 | ### 2. Build and Run 315 | 316 | With Docker Compose building and running are done with one command (run in the project root): 317 | 318 | ```bash 319 | docker compose up 320 | ``` 321 | 322 | 323 | This command will build and run the project serving it on port 8080. 324 | 325 | For further explanations see the comments in file: _docker-compose.yaml_ 326 | 327 | By running `docker compose up` the output will be captured by the execution. 328 | 329 | You can pass the execution context to the docker daemon by running 330 | 331 | ```bash 332 | docker compose up -d 333 | ``` 334 | 335 | ## Cleaning Up 336 | 337 | If you ran `docker compose` without the `-d` flag stop the execution by pressing `ctrl+c` 338 | 339 | If you ran `docker compose -d` you can stop the execution by running 340 | 341 | ```bash 342 | docker compose down 343 | ``` 344 | 345 | within the directory where the file _docker-compose.yaml_ is located 346 | 347 | Run 348 | 349 | ```bash 350 | docker compose rm 351 | ``` 352 | 353 | to remove the stopped container. 354 | 355 | Then do as described in [Cleaning Up for Docker](#cleaning-up) except for the removal of the stopped container part 356 | 357 | ## Troubleshooting (only for Mac or Linux) 358 | 359 | If you get this error: 360 | `Error response from daemon: driver failed programming external connectivity on endpoint helloworld-app-1 (1769c92017f2d2da48adc989bd2321855e3152f6a11932c18ed36e7df443f0ae): failed to bind port 0.0.0.0:8080/tcp: Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use' 361 | ` 362 | 363 | It means the port 8080 is already binded (maybe by the previous docker execution without cleaning up). 364 | 365 | To solve it find the process running on port 8080 by running 366 | 367 | ```bash 368 | lsof -i tcp:8080 369 | ``` 370 | 371 | Note the `PID` value of the output and kill the process by running 372 | 373 | ```bash 374 | kill 375 | ``` 376 | 377 | 378 | --- 379 | 380 | # License 381 | 382 | This project is licensed under the IronAvantgarde Publishing & Napalm Records License - see the [Napalm Records Website](https://napalmrecords.com/) for more details. 383 | 384 | # Contributing 385 | 386 | Feel free to fork this repository, submit issues, or open pull requests if you'd like to improve this code. Contributions are always welcome! 387 | 388 | # Contacts 389 | 390 | **Do you want some buggy, personalized and singable code by Nanowar Of Steel**? Please contact us [here](mailto:nanowar@nanowar.it). 391 | --------------------------------------------------------------------------------