-
Notifications
You must be signed in to change notification settings - Fork 0
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
Showing
4 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
66 changes: 66 additions & 0 deletions
66
jcommons/src/main/java/org/mbari/jcommons/util/CloseableLock.java
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,66 @@ | ||
package org.mbari.jcommons.util; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.locks.Condition; | ||
import java.util.concurrent.locks.Lock; | ||
import java.util.concurrent.locks.ReentrantLock; | ||
|
||
/** | ||
* A wrapper around a ReentrantLock that allows you to use it in a try-with-resources block. | ||
* {@code | ||
* var lock = new CloseableLock(); | ||
* try (lock.lock()) { | ||
* // do something | ||
* } | ||
* } | ||
* | ||
* @see https://debugagent.com/relearning-java-thread-primitives | ||
*/ | ||
public class CloseableLock implements AutoCloseable, Lock { | ||
private final Lock lock; | ||
|
||
public CloseableLock() { | ||
this.lock = new ReentrantLock(); | ||
} | ||
|
||
public CloseableLock(boolean fair) { | ||
this.lock = new ReentrantLock(fair); | ||
} | ||
|
||
|
||
public Lock getLock() { | ||
return lock; | ||
} | ||
|
||
@Override | ||
public void close() throws Exception { | ||
lock.unlock(); | ||
} | ||
|
||
public void lock() { | ||
lock.lock(); | ||
} | ||
|
||
public void lockInterruptibly() throws InterruptedException { | ||
lock.lock(); | ||
} | ||
|
||
public void unlock() { | ||
lock.unlock(); | ||
} | ||
|
||
@Override | ||
public boolean tryLock() { | ||
return lock.tryLock(); | ||
} | ||
|
||
@Override | ||
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { | ||
return lock.tryLock(time, unit); | ||
} | ||
|
||
@Override | ||
public Condition newCondition() { | ||
return lock.newCondition(); | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
scommons/src/main/scala/org/mbari/scommons/etc/jdk/Images.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,54 @@ | ||
package org.mbari.scommons.etc.jdk | ||
|
||
import java.awt.image.{BufferedImage, RenderedImage} | ||
import java.io.{ByteArrayInputStream, ByteArrayOutputStream, IOException} | ||
import java.net.URL | ||
import java.nio.file.{Files, Path} | ||
import java.text.SimpleDateFormat | ||
import java.util.Date | ||
import java.util.TimeZone | ||
import javax.imageio.{IIOImage, ImageIO, ImageTypeSpecifier} | ||
|
||
object Images: | ||
|
||
/** | ||
* Saves the image to the target file. The format of the saved file is determined by it's extension. Will create the | ||
* parent directories if they do not exist. | ||
* | ||
* @param image | ||
* The image to save | ||
* @param target | ||
* The file to save the image to. | ||
* | ||
* @throws IOException | ||
*/ | ||
@throws(classOf[IOException]) | ||
def saveImage(image: RenderedImage, target: Path): Unit = | ||
// Extract the type from the extension | ||
val parent = target.getParent | ||
if Files.notExists(parent) then Files.createDirectories(parent) | ||
val path = target.toAbsolutePath.normalize.toString | ||
val dotIdx = path.lastIndexOf(".") | ||
val ext = path.substring(dotIdx + 1) | ||
ImageIO.write(image, ext, target.toFile) | ||
|
||
/** | ||
* Convert a buffered image to an array of bytes in JPEG format | ||
* @param image | ||
* @return | ||
*/ | ||
def toJpegByteArray(image: BufferedImage): Array[Byte] = toImageByteArray(image, "jpg") | ||
|
||
/** | ||
* Convert a buffered image to an array of bytes in PNG format | ||
* @param image | ||
* @return | ||
*/ | ||
def toPngByteArray(image: BufferedImage): Array[Byte] = toImageByteArray(image, "png") | ||
|
||
private def toImageByteArray(image: BufferedImage, format: String): Array[Byte] = | ||
val os0 = new ByteArrayOutputStream | ||
ImageIO.write(image, format, os0) | ||
val imageBytes = os0.toByteArray | ||
os0.close() | ||
imageBytes |
35 changes: 35 additions & 0 deletions
35
scommons/src/main/scala/org/mbari/scommons/etc/jdk/Instants.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,35 @@ | ||
package org.mbari.scommons.etc.jdk | ||
|
||
import java.time.Instant | ||
import java.time.format.DateTimeFormatter | ||
import scala.util.Try | ||
import java.time.ZoneOffset | ||
import java.time.temporal.ChronoUnit | ||
|
||
object Instants: | ||
|
||
private val compactTimeFormatter = | ||
DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX").withZone(java.time.ZoneOffset.UTC) | ||
|
||
private val formatters = Seq( | ||
compactTimeFormatter, | ||
DateTimeFormatter.ISO_DATE_TIME, | ||
DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSX").withZone(java.time.ZoneOffset.UTC), | ||
DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSSSSX").withZone(java.time.ZoneOffset.UTC), | ||
DateTimeFormatter.ISO_OFFSET_DATE_TIME, | ||
DateTimeFormatter.ISO_INSTANT) | ||
|
||
def parseIso8601(s: String): Option[Instant] = | ||
formatters.to(LazyList).flatMap(tryToParse(s, _)).headOption | ||
|
||
def compactFormat(instant: Instant): String = compactTimeFormatter.format(instant) | ||
|
||
private def tryToParse(s: String, formatter: DateTimeFormatter): Option[Instant] = | ||
Try(Instant.from(formatter.parse(s))).toOption | ||
|
||
def roundToHour(i: Instant): Instant = | ||
val z = i.atZone(ZoneOffset.UTC) | ||
val minutes = z.getMinute() | ||
val adjustedTime = if (minutes >= 30) z.plusHours(1) else z | ||
val truncatedTime = adjustedTime.truncatedTo(ChronoUnit.HOURS) | ||
truncatedTime.toInstant() |
8 changes: 8 additions & 0 deletions
8
scommons/src/main/scala/org/mbari/scommons/etc/jdk/Strings.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,8 @@ | ||
package org.mbari.scommons.etc.jdk | ||
|
||
object Strings: | ||
|
||
def addTrailingSlash(s: String): String = if s.endsWith("/") then s else s + "/" | ||
|
||
def removeTrailingSlash(s: String): String = | ||
if s.endsWith("/") then s.substring(0, s.length - 1) else s |