Skip to content

Commit ccfeacc

Browse files
committed
Merge tag 'release/0.7.7' into develop
[maven-release-plugin] copy for tag release/0.7.7
2 parents 99d2692 + b6d10cc commit ccfeacc

File tree

11 files changed

+1622
-676
lines changed

11 files changed

+1622
-676
lines changed

deployment/web/pom.xml

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,19 @@
3939
<dockerfile.imageName>spline-web-ui</dockerfile.imageName>
4040

4141
<java.version>1.8</java.version>
42-
<scala.version>2.12.13</scala.version>
43-
<scala.compat.version>2.12</scala.compat.version>
42+
<scala.version>2.13.16</scala.version>
43+
<scala.compat.version>2.13</scala.compat.version>
4444
</properties>
4545

4646
<dependencies>
47+
<dependency>
48+
<groupId>org.scala-lang</groupId>
49+
<artifactId>scala-library</artifactId>
50+
</dependency>
51+
<dependency>
52+
<groupId>org.scala-lang</groupId>
53+
<artifactId>scala-reflect</artifactId>
54+
</dependency>
4755
<dependency>
4856
<groupId>za.co.absa.spline.ui</groupId>
4957
<artifactId>ui-core</artifactId>
@@ -57,14 +65,9 @@
5765
<scope>provided</scope>
5866
</dependency>
5967
<dependency>
60-
<groupId>za.co.absa.commons</groupId>
61-
<artifactId>commons_${scala.compat.version}</artifactId>
62-
<version>0.0.27</version>
63-
</dependency>
64-
<dependency>
65-
<groupId>commons-configuration</groupId>
66-
<artifactId>commons-configuration</artifactId>
67-
<version>1.10</version>
68+
<groupId>org.apache.commons</groupId>
69+
<artifactId>commons-configuration2</artifactId>
70+
<version>2.12.0</version>
6871
</dependency>
6972
</dependencies>
7073

@@ -104,11 +107,10 @@
104107
<plugin>
105108
<groupId>net.alchim31.maven</groupId>
106109
<artifactId>scala-maven-plugin</artifactId>
107-
<version>4.5.0</version>
110+
<version>4.9.2</version>
108111
<configuration>
109112
<scalaVersion>${scala.version}</scalaVersion>
110113
<args>
111-
<arg>-target:jvm-${java.version}</arg>
112114
<arg>-feature</arg>
113115
<arg>-deprecation</arg>
114116
<arg>-unchecked</arg>
@@ -118,17 +120,31 @@
118120
<executions>
119121
<execution>
120122
<id>scala-compile</id>
123+
<phase>process-resources</phase>
121124
<goals>
122125
<goal>add-source</goal>
123126
<goal>compile</goal>
124127
</goals>
125128
</execution>
129+
<execution>
130+
<id>scala-test-compile</id>
131+
<phase>process-test-resources</phase>
132+
<goals>
133+
<goal>testCompile</goal>
134+
</goals>
135+
</execution>
136+
<execution>
137+
<id>attach-javadocs</id>
138+
<goals>
139+
<goal>doc-jar</goal>
140+
</goals>
141+
</execution>
126142
</executions>
127143
</plugin>
128144
<plugin>
129145
<groupId>org.apache.maven.plugins</groupId>
130146
<artifactId>maven-dependency-plugin</artifactId>
131-
<version>3.1.2</version>
147+
<version>3.7.1</version>
132148
<executions>
133149
<execution>
134150
<id>copy</id>
@@ -152,7 +168,7 @@
152168

153169
<plugin>
154170
<artifactId>maven-war-plugin</artifactId>
155-
<version>3.2.3</version>
171+
<version>3.4.0</version>
156172
<configuration>
157173
<webResources>
158174
<resource>
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
/*
2+
* Copyright 2025 ABSA Group Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.commons.configuration2
18+
19+
import org.apache.commons.lang3.StringUtils.{isBlank, isNotBlank}
20+
21+
import scala.jdk.CollectionConverters._
22+
import scala.reflect.runtime.universe.{TypeTag, typeOf}
23+
import scala.util.Try
24+
25+
26+
/**
27+
* The object contains extension methods for the [[org.apache.commons.configuration2.Configuration Configuration]] interface.
28+
*/
29+
//noinspection ScalaUnusedSymbol
30+
object ConfigurationImplicits {
31+
32+
/**
33+
* The class wraps the [[org.apache.commons.configuration2.Configuration Configuration]] interface in order to provide extension methods.
34+
*
35+
* @param conf A configuration instance
36+
* @tparam T A specific type implementing the [[org.apache.commons.configuration2.Configuration Configuration]] interface
37+
*/
38+
implicit class ConfigurationRequiredWrapper[T <: Configuration](val conf: T) extends AnyVal {
39+
40+
/**
41+
* Gets a value of an object configuration property and checks whether property exists.
42+
*
43+
* @return A value of an object configuration property if exists, otherwise throws an exception.
44+
*/
45+
def getRequiredObject[A <: AnyRef]: String => A = getRequired[AnyRef](conf.getProperty, null.!=)(_).asInstanceOf[A]
46+
47+
/**
48+
* Gets a value of string configuration property and checks whether property exists.
49+
*
50+
* @return A value of string configuration property if exists, otherwise throws an exception.
51+
*/
52+
def getRequiredString: String => String = getRequired(conf.getString, isNotBlank)
53+
54+
/**
55+
* Gets a value of string array configuration property and checks whether the array is not empty.
56+
*
57+
* @return A value of string array configuration property if not empty, otherwise throws an exception.
58+
*/
59+
def getRequiredStringArray: String => Array[String] = getRequired(conf.getStringArray, (arr: Array[String]) => !arr.forall(isBlank))
60+
61+
/**
62+
* Gets a value of boolean configuration property and checks whether property exists.
63+
*
64+
* @return A value of boolean configuration property if exists, otherwise throws an exception.
65+
*/
66+
def getRequiredBoolean: String => Boolean = getRequired(conf.getBoolean(_, null), null.!=) //NOSONAR
67+
68+
/**
69+
* Gets a value of big decimal configuration property and checks whether property exists.
70+
*
71+
* @return A value of big decimal configuration property if exists, otherwise throws an exception.
72+
*/
73+
def getRequiredBigDecimal: String => BigDecimal = getRequired(conf.getBigDecimal(_, null), null.!=) //NOSONAR
74+
75+
/**
76+
* Gets a value of byte configuration property and checks whether property exists.
77+
*
78+
* @return A value of byte configuration property if exists, otherwise throws an exception.
79+
*/
80+
def getRequiredByte: String => Byte = getRequired(conf.getByte(_, null), null.!=) //NOSONAR
81+
82+
/**
83+
* Gets a value of short configuration property and checks whether property exists.
84+
*
85+
* @return A value of short configuration property if exists, otherwise throws an exception.
86+
*/
87+
def getRequiredShort: String => Short = getRequired(conf.getShort(_, null), null.!=) //NOSONAR
88+
89+
/**
90+
* Gets a value of int configuration property and checks whether property exists.
91+
*
92+
* @return A value of int configuration property if exists, otherwise throws an exception.
93+
*/
94+
def getRequiredInt: String => Int = getRequired(conf.getInteger(_, null), null.!=) //NOSONAR
95+
96+
/**
97+
* Gets a value of long configuration property and checks whether property exists.
98+
*
99+
* @return A value of long configuration property if exists, otherwise throws an exception.
100+
*/
101+
def getRequiredLong: String => Long = getRequired(conf.getLong(_, null), null.!=) //NOSONAR
102+
103+
/**
104+
* Gets a value of float configuration property and checks whether property exists.
105+
*
106+
* @return A value of float configuration property if exists, otherwise throws an exception.
107+
*/
108+
def getRequiredFloat: String => Float = getRequired(conf.getFloat(_, null), null.!=) //NOSONAR
109+
110+
/**
111+
* Gets a value of double configuration property and checks whether property exists.
112+
*
113+
* @return A value of double configuration property if exists, otherwise throws an exception.
114+
*/
115+
def getRequiredDouble: String => Double = getRequired(conf.getDouble(_, null), null.!=) //NOSONAR
116+
117+
private def getRequired[V](get: String => V, check: V => Boolean)(key: String): V = {
118+
Try(get(key))
119+
.filter(check)
120+
.recover {
121+
case _: NoSuchElementException =>
122+
// rewrite exception message for clarity
123+
throw new NoSuchElementException(s"Missing configuration property ${getFullPropName(key)}")
124+
case e: Exception =>
125+
throw new RuntimeException(s"Error in retrieving configuration property ${getFullPropName(key)}", e)
126+
}
127+
.get
128+
}
129+
130+
private def getFullPropName(key: String) = conf match {
131+
case sc: SubsetConfiguration => sc.getParentKey(key)
132+
case _ => key
133+
}
134+
}
135+
136+
/**
137+
* The class wraps the [[org.apache.commons.configuration2.Configuration Configuration]] interface in order to provide extension methods.
138+
*
139+
* @param conf A configuration instance
140+
* @tparam T A specific type implementing the [[org.apache.commons.configuration2.Configuration Configuration]] interface
141+
*/
142+
implicit class ConfigurationOptionalWrapper[T <: Configuration](val conf: T) extends AnyVal {
143+
144+
/**
145+
* Gets a value of an object configuration property.
146+
*
147+
* @return A Some wrapped value of object configuration property if exists, otherwise None.
148+
*/
149+
def getOptionalObject[A <: AnyRef]: String => Option[A] = getOptional[AnyRef](conf.getProperty)(_).map(_.asInstanceOf[A])
150+
151+
/**
152+
* Gets a value of string configuration property.
153+
*
154+
* @return A Some wrapped value of string configuration property if exists, otherwise None.
155+
*/
156+
def getOptionalString: String => Option[String] = getOptional(conf.getString)(_).filter(isNotBlank)
157+
158+
159+
/**
160+
* Gets a value of string array configuration property and checks whether the array is not empty.
161+
*
162+
* @return A Some wrapped value of string array configuration property if not empty, otherwise None.
163+
*/
164+
def getOptionalStringArray: String => Option[Array[String]] = getOptional(conf.getStringArray)(_).filter(_.nonEmpty)
165+
166+
/**
167+
* Gets a value of boolean configuration property.
168+
*
169+
* @return A Some wrapped value of boolean configuration property if exists, otherwise None.
170+
*/
171+
def getOptionalBoolean: String => Option[Boolean] = getOptional(conf.getBoolean)
172+
173+
/**
174+
* Gets a value of big decimal configuration property.
175+
*
176+
* @return A Some wrapped value of big decimal configuration property if exists, otherwise None.
177+
*/
178+
//noinspection ConvertibleToMethodValue
179+
def getOptionalBigDecimal: String => Option[BigDecimal] = getOptional(conf.getBigDecimal(_))
180+
181+
/**
182+
* Gets a value of byte configuration property.
183+
*
184+
* @return A Some wrapped value of byte configuration property if exists, otherwise None.
185+
*/
186+
def getOptionalByte: String => Option[Byte] = getOptional(conf.getByte)
187+
188+
/**
189+
* Gets a value of short configuration property.
190+
*
191+
* @return A Some wrapped value of short configuration property if exists, otherwise None.
192+
*/
193+
def getOptionalShort: String => Option[Short] = getOptional(conf.getShort)
194+
195+
/**
196+
* Gets a value of int configuration property.
197+
*
198+
* @return A Some wrapped value of int configuration property if exists, otherwise None.
199+
*/
200+
def getOptionalInt: String => Option[Int] = getOptional(conf.getInt)
201+
202+
/**
203+
* Gets a value of long configuration property.
204+
*
205+
* @return A Some wrapped value of long configuration property if exists, otherwise None.
206+
*/
207+
def getOptionalLong: String => Option[Long] = getOptional(conf.getLong)
208+
209+
/**
210+
* Gets a value of float configuration property.
211+
*
212+
* @return A Some wrapped value of float configuration property if exists, otherwise None.
213+
*/
214+
def getOptionalFloat: String => Option[Float] = getOptional(conf.getFloat)
215+
216+
/**
217+
* Gets a value of double configuration property.
218+
*
219+
* @return A Some wrapped value of double configuration property if exists, otherwise None.
220+
*/
221+
def getOptionalDouble: String => Option[Double] = getOptional(conf.getDouble)
222+
223+
private def getOptional[V](get: String => V)(key: String): Option[V] = {
224+
if (conf.containsKey(key))
225+
Option(get(key))
226+
else
227+
None
228+
}
229+
230+
}
231+
232+
implicit class ConfigurationMapWrapper(val conf: Configuration) extends AnyVal {
233+
234+
/**
235+
* Converts the configuration into map where keys are Strings and values are converted to U type.
236+
* When the value key is not of proper type it throws.
237+
*
238+
* @tparam U type of values in returned map
239+
* @return map representation of the configuration
240+
*/
241+
def toMap[U: TypeTag]: Map[String, U] =
242+
ConfigurationImplicits.toMap[U](conf)
243+
}
244+
245+
/**
246+
* This method needs to be defined outside of the Value class since Scala has issues with TypeTag in Value classes
247+
*/
248+
private def toMap[U: TypeTag](conf: Configuration): Map[String, U] = {
249+
val fun = typeOf[U] match {
250+
case t if t =:= typeOf[String] => (c: Configuration, k: String) => c.getRequiredString(k)
251+
case t if t =:= typeOf[Boolean] => (c: Configuration, k: String) => c.getRequiredBoolean(k)
252+
case t if t =:= typeOf[BigDecimal] => (c: Configuration, k: String) => c.getRequiredBigDecimal(k)
253+
case t if t =:= typeOf[Byte] => (c: Configuration, k: String) => c.getRequiredByte(k)
254+
case t if t =:= typeOf[Short] => (c: Configuration, k: String) => c.getRequiredShort(k)
255+
case t if t =:= typeOf[Int] => (c: Configuration, k: String) => c.getRequiredInt(k)
256+
case t if t =:= typeOf[Long] => (c: Configuration, k: String) => c.getRequiredLong(k)
257+
case t if t =:= typeOf[Float] => (c: Configuration, k: String) => c.getRequiredFloat(k)
258+
case t if t =:= typeOf[Double] => (c: Configuration, k: String) => c.getRequiredDouble(k)
259+
case t if t =:= typeOf[AnyRef] => (c: Configuration, k: String) => c.getProperty(k)
260+
case t if t =:= typeOf[Array[String]] => (c: Configuration, k: String) => c.getRequiredStringArray(k)
261+
case t => throw new UnsupportedOperationException(s"Type $t not supported")
262+
}
263+
264+
conf
265+
.getKeys.asScala
266+
.map(k => k -> fun(conf, k).asInstanceOf[U])
267+
.toMap
268+
}
269+
270+
271+
}

deployment/web/src/main/scala/za/co/absa/spline/common/config/DefaultConfigurationStack.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package za.co.absa.spline.common.config
1919
import java.util
2020

2121
import javax.naming.InitialContext
22-
import org.apache.commons.configuration._
22+
import org.apache.commons.configuration2._
2323
import za.co.absa.spline.common.config.DefaultConfigurationStack.jndiConfigurationIfAvailable
2424

2525
import scala.util.Try

deployment/web/src/main/scala/za/co/absa/spline/common/config/UpperSnakeCaseEnvironmentConfiguration.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616

1717
package za.co.absa.spline.common.config
1818

19-
import org.apache.commons.configuration.EnvironmentConfiguration
20-
import org.apache.commons.lang.StringUtils
19+
import org.apache.commons.configuration2.EnvironmentConfiguration
20+
import org.apache.commons.lang3.StringUtils
2121
import za.co.absa.spline.common.config.UpperSnakeCaseEnvironmentConfiguration.toUpperSnake
2222

2323
class UpperSnakeCaseEnvironmentConfiguration extends EnvironmentConfiguration {
2424

25-
override def getProperty(key: String): AnyRef = super.getProperty(toUpperSnake(key))
25+
override def getPropertyInternal(key: String): AnyRef = super.getPropertyInternal(toUpperSnake(key))
2626

27-
override def containsKey(key: String): Boolean = super.containsKey(toUpperSnake(key))
27+
override def containsKeyInternal(key: String): Boolean = super.containsKeyInternal(toUpperSnake(key))
2828
}
2929

3030
object UpperSnakeCaseEnvironmentConfiguration {

0 commit comments

Comments
 (0)