Skip to content

Commit 8f8cf5c

Browse files
authored
Merge branch 'eugenp:master' into BAEL-8657
2 parents 3804568 + b02e6a2 commit 8f8cf5c

File tree

75 files changed

+2637
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+2637
-8
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.baeldung.algorithms.bcdtodecimal;
2+
3+
public class BCDtoDecimalConverter {
4+
/**
5+
* Converts a single packed BCD byte to an integer.
6+
* Each byte represents two decimal digits.
7+
*
8+
* @param bcdByte The BCD byte to convert.
9+
* @return The decimal integer value.
10+
* @throws IllegalArgumentException if any nibble contains a non-BCD value (>9).
11+
*/
12+
public static int convertPackedByte(byte bcdByte) {
13+
int resultDecimal;
14+
int upperNibble = (bcdByte >> 4) & 0x0F;
15+
int lowerNibble = bcdByte & 0x0F;
16+
if (upperNibble > 9 || lowerNibble > 9) {
17+
throw new IllegalArgumentException(
18+
String.format("Invalid BCD format: byte 0x%02X contains non-decimal digit.", bcdByte)
19+
);
20+
}
21+
resultDecimal = upperNibble * 10 + lowerNibble;
22+
return resultDecimal;
23+
}
24+
25+
/**
26+
* Converts a BCD byte array to a long decimal value.
27+
* Each byte in the array iis mapped to a packed BCD byte,
28+
* representing two BCD nibbles.
29+
*
30+
* @param bcdArray The array of BCD bytes.
31+
* @return The combined long decimal value.
32+
* @throws IllegalArgumentException if any nibble contains a non-BCD value (>9).
33+
*/
34+
public static long convertPackedByteArray(byte[] bcdArray) {
35+
long resultDecimal = 0;
36+
for (byte bcd : bcdArray) {
37+
int upperNibble = (bcd >> 4) & 0x0F;
38+
int lowerNibble = bcd & 0x0F;
39+
40+
if (upperNibble > 9 || lowerNibble > 9) {
41+
throw new IllegalArgumentException("Invalid BCD format: nibble contains non-decimal digit.");
42+
}
43+
44+
resultDecimal = resultDecimal * 100 + (upperNibble * 10 + lowerNibble);
45+
}
46+
return resultDecimal;
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Package to host code for calculating three types of angle difference
3+
*/
4+
package com.baeldung.algorithms.twoanglesdifference;
5+
6+
public class AngleDifferenceCalculator {
7+
8+
/**
9+
* Normalizes an angle to be within the range [0, 360).
10+
*
11+
* @param angle The angle in degrees.
12+
* @return The normalized angle.
13+
*/
14+
public static double normalizeAngle(double angle) {
15+
return (angle % 360 + 360) % 360;
16+
}
17+
18+
/**
19+
* Calculates the absolute difference between two angles.
20+
*
21+
* @param angle1 The first angle in degrees.
22+
* @param angle2 The second angle in degrees.
23+
* @return The absolute difference in degrees.
24+
*/
25+
public static double absoluteDifference(double angle1, double angle2) {
26+
return Math.abs(angle1 - angle2);
27+
}
28+
29+
/**
30+
* Calculates the shortest difference between two angles.
31+
*
32+
* @param angle1 The first angle in degrees.
33+
* @param angle2 The second angle in degrees.
34+
* @return The shortest difference in degrees (0 to 180).
35+
*/
36+
public static double shortestDifference(double angle1, double angle2) {
37+
double diff = absoluteDifference(normalizeAngle(angle1), normalizeAngle(angle2));
38+
return Math.min(diff, 360 - diff);
39+
}
40+
41+
/**
42+
* Calculates the signed shortest difference between two angles.
43+
* A positive result indicates counter-clockwise rotation, a negative result indicates clockwise.
44+
*
45+
* @param angle1 The first angle in degrees.
46+
* @param angle2 The second angle in degrees.
47+
* @return The signed shortest difference in degrees (-180 to 180).
48+
*/
49+
public static double signedShortestDifference(double angle1, double angle2) {
50+
double normalizedAngle1 = normalizeAngle(angle1);
51+
double normalizedAngle2 = normalizeAngle(angle2);
52+
double diff = normalizedAngle2 - normalizedAngle1;
53+
54+
if (diff > 180) {
55+
return diff - 360;
56+
} else if (diff < -180) {
57+
return diff + 360;
58+
} else {
59+
return diff;
60+
}
61+
}
62+
}
63+
64+
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.baeldung.algorithms.bcdtodecimal;
2+
3+
import org.junit.jupiter.api.Test;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
public class BCDtoDecimalConverterTest {
8+
9+
// 1. Tests for convertPackedByte(byte bcdByte)
10+
11+
@Test
12+
void testConvertPackedByteValidValues() {
13+
// Test 05 (0x05) ->
14+
assertEquals(5, BCDtoDecimalConverter.convertPackedByte((byte) 0x05));
15+
16+
// Test 22 (0x22) -> 22
17+
assertEquals(22, BCDtoDecimalConverter.convertPackedByte((byte) 0x22));
18+
19+
// Test 97 (0x097) -> 97
20+
assertEquals(97, BCDtoDecimalConverter.convertPackedByte((byte) 0x097));
21+
}
22+
23+
@Test
24+
void testConvertPackedByteInvalidUpperNibbleThrowsException() {
25+
// Test Upper nibble is A (1010), Lower nibble is 1 (0001) -> 0xA1
26+
byte invalidByte = (byte) 0xA1;
27+
assertThrows(IllegalArgumentException.class, () -> BCDtoDecimalConverter.convertPackedByte(invalidByte),
28+
"Received non-BCD upper nibble (A). Provide valid BCD nibbles (0-9).");
29+
}
30+
31+
@Test
32+
void testConvertPackedByteBothInvalidThrowsException() {
33+
// test Upper nibble is B, Lower nibble is E -> 0xBE
34+
byte invalidByte = (byte) 0xBE;
35+
assertThrows(IllegalArgumentException.class,
36+
() -> BCDtoDecimalConverter.convertPackedByte(invalidByte),
37+
"Received both nibbles as non-BCD. Provide valid BCD nibbles (0-9)."
38+
);
39+
}
40+
41+
// -------------------------------------------------------------------------
42+
43+
// 2. Tests for convertPackedByteArray(byte[] bcdArray)
44+
45+
@Test
46+
void testConvertPackedByteArrayValidValues() {
47+
// Test 0 -> [0x00]
48+
assertEquals(0L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{(byte) 0x00}));
49+
50+
// Test 99 -> [0x99]
51+
assertEquals(99L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{(byte) 0x99}));
52+
53+
// Test 1234 -> [0x12, 0x34]
54+
byte[] bcd1234 = {(byte) 0x12, (byte) 0x34};
55+
assertEquals(1234L, BCDtoDecimalConverter.convertPackedByteArray(bcd1234));
56+
57+
// Test 12345678 -> [0x12, 0x34, 0x56, 0x78]
58+
byte[] bcdLarge = {(byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78};
59+
assertEquals(12345678L, BCDtoDecimalConverter.convertPackedByteArray(bcdLarge));
60+
}
61+
62+
@Test
63+
void testConvertPackedByteArrayEmptyArray() {
64+
// Test empty array -> 0
65+
assertEquals(0L, BCDtoDecimalConverter.convertPackedByteArray(new byte[]{}));
66+
}
67+
68+
@Test
69+
void testConvertPackedByteArrayMaximumSafeLong() {
70+
// Test a large number that fits within a long (18 digits)
71+
// 999,999,999,999,999,999 (18 nines)
72+
byte[] bcdMax = {(byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99, (byte) 0x99};
73+
assertEquals(999999999999999999L, BCDtoDecimalConverter.convertPackedByteArray(bcdMax));
74+
}
75+
76+
@Test
77+
void testConvertPackedByteArrayInvalidNibbleThrowsException() {
78+
// Contains 0x1A (A is an invalid BCD digit)
79+
byte[] bcdInvalid = {(byte) 0x12, (byte) 0x1A, (byte) 0x34};
80+
assertThrows(IllegalArgumentException.class,
81+
() -> BCDtoDecimalConverter.convertPackedByteArray(bcdInvalid),
82+
"Received array containing an invalid BCD byte. Provide valid BCD nibbles (0-9)."
83+
);
84+
}
85+
86+
@Test
87+
void testConvertPackedByteArray_InvalidFirstByteThrowsException() {
88+
// Invalid BCD byte at the start
89+
byte[] bcdInvalid = {(byte) 0xF0, (byte) 0x12};
90+
assertThrows(IllegalArgumentException.class,
91+
() -> BCDtoDecimalConverter.convertPackedByteArray(bcdInvalid),
92+
"Received first byte as an invalid BCD byte. Provide valid BCD nibbles (0-9)."
93+
);
94+
}
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Package to host JUnit Test code for AngleDifferenceCalculator Class
3+
*/
4+
package com.baeldung.algorithms.twoanglesdifference;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
11+
12+
class AngleDifferenceCalculatorTest {
13+
14+
private static final double EPSILON = 0.0001;
15+
16+
@Test
17+
void whenNormalizingAngle_thenReturnsCorrectRange() {
18+
assertEquals(90, AngleDifferenceCalculator.normalizeAngle(450), EPSILON);
19+
assertEquals(30, AngleDifferenceCalculator.normalizeAngle(390), EPSILON);
20+
assertEquals(330, AngleDifferenceCalculator.normalizeAngle(-30), EPSILON);
21+
assertEquals(0, AngleDifferenceCalculator.normalizeAngle(360), EPSILON);
22+
}
23+
24+
@Test
25+
void whenCalculatingAbsoluteDifference_thenReturnsCorrectValue() {
26+
assertEquals(100, AngleDifferenceCalculator.absoluteDifference(10, 110), EPSILON);
27+
assertEquals(290, AngleDifferenceCalculator.absoluteDifference(10, 300), EPSILON);
28+
assertEquals(30, AngleDifferenceCalculator.absoluteDifference(-30, 0), EPSILON);
29+
}
30+
31+
@Test
32+
void whenCalculatingShortestDifference_thenReturnsCorrectValue() {
33+
assertEquals(100, AngleDifferenceCalculator.shortestDifference(10, 110), EPSILON);
34+
assertEquals(70, AngleDifferenceCalculator.shortestDifference(10, 300), EPSILON);
35+
assertEquals(30, AngleDifferenceCalculator.shortestDifference(-30, 0), EPSILON);
36+
assertEquals(0, AngleDifferenceCalculator.shortestDifference(360, 0), EPSILON);
37+
}
38+
39+
@Test
40+
void whenCalculatingSignedShortestDifference_thenReturnsCorrectValue() {
41+
assertEquals(100, AngleDifferenceCalculator.signedShortestDifference(10, 110), EPSILON);
42+
assertEquals(-70, AngleDifferenceCalculator.signedShortestDifference(10, 300), EPSILON);
43+
assertEquals(30, AngleDifferenceCalculator.signedShortestDifference(-30, 0), EPSILON);
44+
assertEquals(70, AngleDifferenceCalculator.signedShortestDifference(300, 10), EPSILON);
45+
}
46+
}
47+

apache-spark-2/pom.xml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<artifactId>apache-spark-2</artifactId>
7+
<version>1.0-SNAPSHOT</version>
8+
<packaging>jar</packaging>
9+
<name>apache-spark</name>
10+
11+
<parent>
12+
<groupId>com.baeldung</groupId>
13+
<artifactId>parent-modules</artifactId>
14+
<version>1.0.0-SNAPSHOT</version>
15+
</parent>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>io.delta</groupId>
20+
<artifactId>delta-core_2.12</artifactId>
21+
<version>${delta-core.version}</version>
22+
</dependency>
23+
<dependency>
24+
<groupId>org.apache.spark</groupId>
25+
<artifactId>spark-core_2.12</artifactId>
26+
<version>${org.apache.spark.spark-core.version}</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>org.apache.spark</groupId>
30+
<artifactId>spark-sql_2.12</artifactId>
31+
<version>${org.apache.spark.spark-sql.version}</version>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<plugins>
37+
<plugin>
38+
<artifactId>maven-assembly-plugin</artifactId>
39+
<version>3.3.0</version>
40+
<executions>
41+
<execution>
42+
<phase>package</phase>
43+
<goals>
44+
<goal>single</goal>
45+
</goals>
46+
</execution>
47+
</executions>
48+
<configuration>
49+
<descriptorRefs>
50+
<descriptorRef>jar-with-dependencies</descriptorRef>
51+
</descriptorRefs>
52+
</configuration>
53+
</plugin>
54+
</plugins>
55+
</build>
56+
57+
<repositories>
58+
<repository>
59+
<id>SparkPackagesRepo</id>
60+
<url>https://repos.spark-packages.org</url>
61+
</repository>
62+
</repositories>
63+
64+
<properties>
65+
<delta-core.version>2.4.0</delta-core.version>
66+
<org.apache.spark.spark-core.version>3.4.0</org.apache.spark.spark-core.version>
67+
<org.apache.spark.spark-sql.version>3.4.0</org.apache.spark.spark-sql.version>
68+
<maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version>
69+
</properties>
70+
</project>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.baeldung.delta;
2+
3+
import org.apache.spark.sql.*;
4+
import java.io.Serializable;
5+
import java.nio.file.Files;
6+
7+
public class DeltaLake {
8+
public static SparkSession createSession() {
9+
return SparkSession.builder()
10+
.appName("DeltaLake")
11+
.master("local[*]")
12+
.config("spark.sql.extensions", "io.delta.sql.DeltaSparkSessionExtension")
13+
.config("spark.sql.catalog.spark_catalog", "org.apache.spark.sql.delta.catalog.DeltaCatalog")
14+
.getOrCreate();
15+
}
16+
17+
public static String preparePeopleTable(SparkSession spark) {
18+
try {
19+
String tablePath = Files.createTempDirectory("delta-table-").toAbsolutePath().toString();
20+
21+
Dataset<Row> data = spark.createDataFrame(
22+
java.util.Arrays.asList(
23+
new Person(1, "Alice"),
24+
new Person(2, "Bob")
25+
),
26+
Person.class
27+
);
28+
29+
data.write().format("delta").mode("overwrite").save(tablePath);
30+
spark.sql("DROP TABLE IF EXISTS people");
31+
spark.sql("CREATE TABLE IF NOT EXISTS people USING DELTA LOCATION '" + tablePath + "'");
32+
return tablePath;
33+
} catch (Exception e) {
34+
throw new RuntimeException(e);
35+
}
36+
}
37+
38+
public static void cleanupPeopleTable(SparkSession spark) {
39+
spark.sql("DROP TABLE IF EXISTS people");
40+
}
41+
42+
public static void stopSession(SparkSession spark) {
43+
if (spark != null) {
44+
spark.stop();
45+
}
46+
}
47+
48+
public static class Person implements Serializable {
49+
private int id;
50+
private String name;
51+
52+
public Person() {}
53+
public Person(int id, String name) { this.id = id; this.name = name; }
54+
55+
public int getId() { return id; }
56+
public void setId(int id) { this.id = id; }
57+
public String getName() { return name; }
58+
public void setName(String name) { this.name = name; }
59+
}
60+
}

0 commit comments

Comments
 (0)