-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Simon Dumas
committed
Aug 25, 2023
1 parent
90e7eb7
commit 02ca26d
Showing
11 changed files
with
244 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
.../scala/ch/epfl/bluebrain/nexus/delta/kernel/utils/CatsEffectsClasspathResourceUtils.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package ch.epfl.bluebrain.nexus.delta.kernel.utils | ||
|
||
import cats.effect.IO | ||
import cats.syntax.all._ | ||
import ch.epfl.bluebrain.nexus.delta.kernel.utils.CatsEffectsClasspathResourceUtilsStatic.handleBars | ||
import ch.epfl.bluebrain.nexus.delta.kernel.utils.ClasspathResourceError.{InvalidJson, InvalidJsonObject, ResourcePathNotFound} | ||
import com.github.jknack.handlebars.{EscapingStrategy, Handlebars} | ||
import io.circe.parser.parse | ||
import io.circe.{Json, JsonObject} | ||
|
||
import java.io.InputStream | ||
import java.util.Properties | ||
import scala.io.{Codec, Source} | ||
import scala.jdk.CollectionConverters._ | ||
|
||
trait CatsEffectsClasspathResourceUtils { | ||
|
||
final def absolutePath(resourcePath: String)(implicit classLoader: ClassLoader): IO[String] = { | ||
val fromResourceOrClassLoader = | ||
Option(getClass.getResource(resourcePath)) orElse Option(classLoader.getResource(resourcePath)) | ||
IO.fromOption(fromResourceOrClassLoader)(ResourcePathNotFound(resourcePath)).map(_.getPath) | ||
} | ||
|
||
/** | ||
* Loads the content of the argument classpath resource as an [[InputStream]]. | ||
* | ||
* @param resourcePath | ||
* the path of a resource available on the classpath | ||
* @return | ||
* the content of the referenced resource as an [[InputStream]] or a [[ClasspathResourceError]] when the resource | ||
* is not found | ||
*/ | ||
def ioStreamOf(resourcePath: String)(implicit classLoader: ClassLoader): IO[InputStream] = | ||
IO.defer { | ||
lazy val fromClass = Option(getClass.getResourceAsStream(resourcePath)) | ||
val fromClassLoader = Option(classLoader.getResourceAsStream(resourcePath)) | ||
IO.fromOption(fromClass orElse fromClassLoader)(ResourcePathNotFound(resourcePath)) | ||
} | ||
|
||
/** | ||
* Loads the content of the argument classpath resource as a string and replaces all the key matches of the | ||
* ''replacements'' with their values. | ||
* | ||
* @param resourcePath | ||
* the path of a resource available on the classpath | ||
* @return | ||
* the content of the referenced resource as a string or a [[ClasspathResourceError]] when the resource is not | ||
* found | ||
*/ | ||
final def ioContentOf( | ||
resourcePath: String, | ||
attributes: (String, Any)* | ||
)(implicit classLoader: ClassLoader): IO[String] = | ||
resourceAsTextFrom(resourcePath).map { | ||
case text if attributes.isEmpty => text | ||
case text => handleBars.compileInline(text).apply(attributes.toMap.asJava) | ||
} | ||
|
||
/** | ||
* Loads the content of the argument classpath resource as a java Properties and transforms it into a Map of key | ||
* property and property value. | ||
* | ||
* @param resourcePath | ||
* the path of a resource available on the classpath | ||
* @return | ||
* the content of the referenced resource as a map of properties or a [[ClasspathResourceError]] when the resource | ||
* is not found | ||
*/ | ||
final def ioPropertiesOf(resourcePath: String)(implicit | ||
classLoader: ClassLoader | ||
): IO[Map[String, String]] = | ||
ioStreamOf(resourcePath).map { is => | ||
val props = new Properties() | ||
props.load(is) | ||
props.asScala.toMap | ||
} | ||
|
||
/** | ||
* Loads the content of the argument classpath resource as a string and replaces all the key matches of the | ||
* ''replacements'' with their values. The resulting string is parsed into a json value. | ||
* | ||
* @param resourcePath | ||
* the path of a resource available on the classpath | ||
* @return | ||
* the content of the referenced resource as a json value or an [[ClasspathResourceError]] when the resource is not | ||
* found or is not a Json | ||
*/ | ||
final def ioJsonContentOf( | ||
resourcePath: String, | ||
attributes: (String, Any)* | ||
)(implicit classLoader: ClassLoader): IO[Json] = | ||
for { | ||
text <- ioContentOf(resourcePath, attributes: _*) | ||
json <- IO.fromEither(parse(text).leftMap(InvalidJson(resourcePath, text, _))) | ||
} yield json | ||
|
||
/** | ||
* Loads the content of the argument classpath resource as a string and replaces all the key matches of the | ||
* ''replacements'' with their values. The resulting string is parsed into a json object. | ||
* | ||
* @param resourcePath | ||
* the path of a resource available on the classpath | ||
* @return | ||
* the content of the referenced resource as a json value or an [[ClasspathResourceError]] when the resource is not | ||
* found or is not a Json | ||
*/ | ||
final def ioJsonObjectContentOf(resourcePath: String, attributes: (String, Any)*)(implicit | ||
classLoader: ClassLoader | ||
): IO[JsonObject] = | ||
for { | ||
json <- ioJsonContentOf(resourcePath, attributes: _*) | ||
jsonObj <- IO.fromOption(json.asObject)(InvalidJsonObject(resourcePath)) | ||
} yield jsonObj | ||
|
||
private def resourceAsTextFrom(resourcePath: String)(implicit | ||
classLoader: ClassLoader | ||
): IO[String] = | ||
ioStreamOf(resourcePath).map(is => Source.fromInputStream(is)(Codec.UTF8).mkString) | ||
} | ||
|
||
object CatsEffectsClasspathResourceUtilsStatic { | ||
private[utils] val handleBars = new Handlebars().`with`(EscapingStrategy.NOOP) | ||
} | ||
|
||
object CatsEffectsClasspathResourceUtils extends CatsEffectsClasspathResourceUtils |
36 changes: 36 additions & 0 deletions
36
...el/src/main/scala/ch/epfl/bluebrain/nexus/delta/kernel/utils/ClasspathResourceError.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package ch.epfl.bluebrain.nexus.delta.kernel.utils | ||
|
||
import io.circe.ParsingFailure | ||
|
||
/** | ||
* Enumeration of possible errors when retrieving resources from the classpath | ||
*/ | ||
sealed abstract class ClasspathResourceError(reason: String) extends Exception with Product with Serializable { | ||
override def fillInStackTrace(): ClasspathResourceError = this | ||
override def getMessage: String = reason | ||
override def toString: String = reason | ||
} | ||
|
||
object ClasspathResourceError { | ||
|
||
/** | ||
* A retrieved resource from the classpath is not a Json | ||
*/ | ||
final case class InvalidJson(resourcePath: String, raw: String, failure: ParsingFailure) | ||
extends ClasspathResourceError( | ||
s"The resource path '$resourcePath' could not be converted to Json because of failure: $failure.\nResource content is:\n$raw" | ||
) | ||
|
||
/** | ||
* A retrieved resource from the classpath is not a Json object | ||
*/ | ||
final case class InvalidJsonObject(resourcePath: String) | ||
extends ClasspathResourceError(s"The resource path '$resourcePath' could not be converted to Json object") | ||
|
||
/** | ||
* The resource cannot be found on the classpath | ||
*/ | ||
final case class ResourcePathNotFound(resourcePath: String) | ||
extends ClasspathResourceError(s"The resource path '$resourcePath' could not be found") | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.