Skip to content

Commit b9d8d41

Browse files
authored
Merge pull request #42 from gmuth/develop
Prepare 3.4 release
2 parents 305344d + db01a01 commit b9d8d41

21 files changed

+304
-169
lines changed

.github/workflows/build.yml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,31 @@ jobs:
1919
steps:
2020
# https://github.com/marketplace/actions/checkout
2121
- name: Checkout sources
22-
uses: actions/checkout@v4
22+
uses: actions/checkout@v5
2323
with:
2424
# Disabling shallow clone is recommended for improving relevancy of reporting
2525
fetch-depth: 0
2626

2727
# https://github.com/marketplace/actions/setup-java-jdk
2828
- name: Setup JDK 17
29-
uses: actions/setup-java@v4
29+
uses: actions/setup-java@v5
3030
with:
3131
distribution: 'temurin'
3232
java-version: '17'
33-
cache: 'gradle'
33+
#cache: 'gradle'
34+
35+
#- name: Show Gradle Version
36+
# run: gradle --version
37+
# 9.x
3438

3539
# https://github.com/marketplace/actions/build-with-gradle
36-
#- name: Setup Gradle
37-
# uses: gradle/actions/setup-gradle@v4
38-
- name: Gradle wrapper build and analyse
39-
run: ./gradlew --no-daemon sonar
40+
- name: Setup Gradle 7
41+
uses: gradle/actions/setup-gradle@v4
42+
with:
43+
gradle-version: '7.6.6'
44+
cache-read-only: 'false'
45+
- name: Gradle build and analyse
46+
run: gradle sonar
4047

4148
# - name: Publish GitHub Packages
4249
# env:

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ RFCs
1313
[![Build](https://github.com/gmuth/ipp-client-kotlin/workflows/build/badge.svg)](https://github.com/gmuth/ipp-client-kotlin/actions?query=workflow%3Abuild)
1414
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=gmuth_ipp-client-kotlin&metric=alert_status)](https://sonarcloud.io/summary/overall?id=gmuth_ipp-client-kotlin)
1515
[![Sonar Coverage](https://img.shields.io/sonar/coverage/gmuth_ipp-client-kotlin?color=00AA00&server=https%3A%2F%2Fsonarcloud.io)](https://sonarcloud.io/component_measures?metric=Coverage&view=list&id=gmuth_ipp-client-kotlin)
16-
[![Maven Central](https://img.shields.io/maven-central/v/de.gmuth/ipp-client.svg?label=maven%20central)](https://central.sonatype.com/artifact/de.gmuth/ipp-client/3.2/overview)
16+
[![Maven Central](https://img.shields.io/maven-central/v/de.gmuth/ipp-client.svg?label=maven%20central)](https://central.sonatype.com/artifact/de.gmuth/ipp-client/3.4/overview)
1717

1818
## Usage
1919

@@ -23,7 +23,7 @@ supports printer lookup by queue name.
2323
Repository [ipp-samples](https://github.com/gmuth/ipp-samples) contains examples how to use jmDNS.
2424

2525
```
26-
implementation("de.gmuth:ipp-client:3.3")
26+
implementation("de.gmuth:ipp-client:3.4")
2727
```
2828

2929
[README.md for version 2.x](https://github.com/gmuth/ipp-client-kotlin/blob/2.5/README.md) is still available.
@@ -219,7 +219,7 @@ Only when the library detects IPP issues through response codes, it consults the
219219

220220
This library implements a different concept then jipp.
221221
jipp seems very strict about IPP syntax and is not designed to cope with illegal IPP responses.
222-
My IPP library in contrast is designed for resilience. E.g. it accepts messages and attributes that use wrong IPP tags.
222+
Library ipp-client in contrast is designed for resilience. E.g. it accepts messages and attributes that use wrong IPP tags.
223223
I've not yet seen any IPP server implementation without a single encoding bug.
224224
[IppInputStream](https://github.com/gmuth/ipp-client-kotlin/blob/master/src/main/kotlin/de/gmuth/ipp/core/IppInputStream.kt)
225225
for example includes workarounds for

build.gradle.kts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import org.jetbrains.dokka.gradle.DokkaTask
44
// where is the jar? build/lib/ipp-client-kotlin...jar
55

66
// update gradle wrapper
7-
// ./gradlew wrapper --gradle-version 7.6.4
7+
// ./gradlew wrapper --gradle-version 7.6.6
88
// gradle 8? should be done when moved to kotlin.jvm plugin 1.9.x (to remove deprecation warnings)
99

1010
plugins {
@@ -16,10 +16,11 @@ plugins {
1616
id("java-library") // https://docs.gradle.org/7.6.2/userguide/java_library_plugin.html
1717
id("signing") // https://docs.gradle.org/7.6.2/userguide/signing_plugin.html
1818
id("jacoco") // https://docs.gradle.org/7.6.2/userguide/jacoco_plugin.html
19+
//kotlin("jvm")
1920
}
2021

2122
group = "de.gmuth"
22-
version = "3.4-SNAPSHOT"
23+
version = "3.4"
2324

2425
repositories {
2526
mavenCentral()
@@ -28,6 +29,7 @@ repositories {
2829
dependencies {
2930
testImplementation("org.jetbrains.kotlin:kotlin-test")
3031
//testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
32+
//implementation(kotlin("stdlib-jdk8"))
3133
}
3234

3335
// gradlew clean -x test build publishToMavenLocal
@@ -38,19 +40,19 @@ val javaVersion = "1.8" // JvmTarget.JVM_1_6, default depends on kotlin release
3840
val kotlinVersion = "1.7"
3941
tasks.apply {
4042

41-
// Kotlin
42-
compileKotlin {
43-
kotlinOptions {
44-
jvmTarget = javaVersion
45-
languageVersion = kotlinVersion
46-
}
47-
}
48-
compileTestKotlin {
49-
kotlinOptions {
50-
jvmTarget = javaVersion
51-
languageVersion = kotlinVersion
52-
}
53-
}
43+
// // Kotlin
44+
// compileKotlin {
45+
// kotlinOptions {
46+
// jvmTarget = javaVersion
47+
// languageVersion = kotlinVersion
48+
// }
49+
// }
50+
// compileTestKotlin {
51+
// kotlinOptions {
52+
// jvmTarget = javaVersion
53+
// languageVersion = kotlinVersion
54+
// }
55+
// }
5456

5557
// Java
5658
// compileJava {
@@ -61,6 +63,15 @@ tasks.apply {
6163
// sourceCompatibility = javaVersion
6264
// targetCompatibility = javaVersion
6365
// }
66+
jar {
67+
manifest {
68+
attributes(
69+
"Maven-Artifact-Name" to project.name,
70+
"Maven-Artifact-Group" to project.group,
71+
"Maven-Artifact-Version" to project.version
72+
)
73+
}
74+
}
6475
}
6576

6677
// ================= PUBLISHING ================
@@ -223,4 +234,8 @@ tasks.sonar {
223234
// duplicatesStrategy = DuplicatesStrategy.EXCLUDE
224235
// from(configurations.runtimeClasspath.get().map(::zipTree))
225236
// with(tasks.jar.get())
237+
//}
238+
239+
//kotlin {
240+
// jvmToolchain(17)
226241
//}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.6-bin.zip
44
networkTimeout=10000
55
zipStoreBase=GRADLE_USER_HOME
66
zipStorePath=wrapper/dists
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package de.gmuth.ipp
2+
3+
import de.gmuth.ipp.client.IppClient
4+
import java.util.jar.Manifest
5+
6+
/**
7+
* Copyright (c) 2025 Gerhard Muth
8+
*/
9+
10+
class Manifest {
11+
companion object {
12+
private val instance = Manifest(IppClient::class.java.getResourceAsStream("/META-INF/MANIFEST.MF"))
13+
val mainAttributes = instance.mainAttributes
14+
val mavenArtifactName = mainAttributes.getValue("Maven-Artifact-Name")
15+
val mavenArtifactGroup = mainAttributes.getValue("Maven-Artifact-Group")
16+
val mavenArtifactVersion = mainAttributes.getValue("Maven-Artifact-Version")
17+
}
18+
}

src/main/kotlin/de/gmuth/ipp/client/CupsClient.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import de.gmuth.ipp.core.IppTag.*
1515
import java.io.File
1616
import java.io.InputStream
1717
import java.net.URI
18+
import java.nio.file.Path
1819
import java.time.Duration
1920
import java.util.concurrent.atomic.AtomicInteger
2021
import java.util.logging.Logger.getLogger
@@ -24,14 +25,15 @@ class CupsClient(
2425
val cupsUri: URI = URI.create("ipps://localhost"),
2526
val ippClient: IppClient = IppClient()
2627
) {
27-
constructor(cupsUri: URI) : this(cupsUri, IppClient())
28+
@JvmOverloads
29+
constructor(cupsUri: URI = URI.create("ipps://localhost")) : this(cupsUri, IppClient())
2830

2931
private val logger = getLogger(javaClass.name)
3032
val config: IppConfig by ippClient::config
3133
var userName: String? by config::userName
3234

3335
var cupsDirectory = with(cupsUri) {
34-
File("CUPS" + (if (host in listOf("localhost", "127.0.0.1")) "-" else File.separator) + host)
36+
Path.of("CUPS" + (if (host in listOf("localhost", "127.0.0.1")) "-" else File.separator) + host)
3537
}
3638

3739
private val cupsServer =
@@ -75,8 +77,9 @@ class CupsClient(
7577

7678
fun getPrinter(printerName: String) =
7779
try {
78-
IppPrinter(printerUri = cupsPrinterUri(printerName), ippClient = ippClient)
79-
.apply { printerDirectory = File(cupsDirectory, printerName).createDirectoryIfNotExists() }
80+
IppPrinter(cupsPrinterUri(printerName), ippClient = ippClient).apply {
81+
printerDirectory = cupsDirectory.resolve(printerName)
82+
}
8083
} catch (clientErrorNotFoundException: ClientErrorNotFoundException) {
8184
with(getPrinters()) {
8285
if (isNotEmpty()) logger.warning { "Available CUPS printers: ${map { it.name }}" }
@@ -327,7 +330,7 @@ class CupsClient(
327330
useJobOwnerAsUserName = true
328331
cupsGetDocuments(
329332
save = true,
330-
directory = File(cupsDirectory, printerUri.path.substringAfterLast("/")),
333+
directory = cupsDirectory.resolve(printerUri.path.substringAfterLast("/")),
331334
optionalCommandToHandleFile = commandToHandleSavedFile
332335
)
333336
.apply { numberOfSavedDocuments.addAndGet(size) }

src/main/kotlin/de/gmuth/ipp/client/IppClient.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ import de.gmuth.ipp.core.IppTag.Unsupported
1414
import de.gmuth.ipp.core.appendAttributeIfGroupContainsKey
1515
import de.gmuth.ipp.iana.IppRegistrationsSection2
1616
import java.io.ByteArrayInputStream
17-
import java.io.File
1817
import java.io.IOException
1918
import java.io.InputStream
2019
import java.net.HttpURLConnection
2120
import java.net.URI
21+
import java.nio.file.Path
2222
import java.util.concurrent.atomic.AtomicInteger
2323
import java.util.logging.Level.FINEST
2424
import java.util.logging.Level.WARNING
@@ -37,11 +37,11 @@ open class IppClient(val config: IppConfig = IppConfig()) {
3737
var saveEvents: Boolean = false
3838
var saveMessages: Boolean = false
3939
var saveDocuments: Boolean = false
40-
var saveMessagesDirectory: File = createTempDirectory().toFile()
40+
var saveMessagesDirectory: Path = createTempDirectory()
4141
var onExceptionSaveMessages: Boolean = false
4242
var throwWhenNotSuccessful: Boolean = true
4343
var disconnectAfterHttpPost: Boolean = false
44-
var defaultPrinterUri: URI? = URI.create("ipp://ippbin:12345")
44+
var defaultPrinterUri: URI? = URI.create("ipp://ippbin.net:12345")
4545

4646
fun basicAuth(user: String, password: String) {
4747
config.userName = user
@@ -167,7 +167,7 @@ open class IppClient(val config: IppConfig = IppConfig()) {
167167
if (status == ClientErrorNotFound) ClientErrorNotFoundException(request, response)
168168
else IppOperationException(request, response)
169169
if (onExceptionSaveMessages)
170-
exception.saveMessages("${request.operation}_${status}_${request.requestId}")
170+
exception.saveMessages(fileNameWithoutSuffix = "${request.operation}_${status}_${request.requestId}")
171171
if (throwWhenNotSuccessful)
172172
throw exception
173173
}
@@ -229,7 +229,9 @@ open class IppClient(val config: IppConfig = IppConfig()) {
229229
read(contentStream)
230230
} catch (throwable: Throwable) {
231231
throw IppOperationException(request, this, "Failed to decode ipp response", throwable).apply {
232-
if (onExceptionSaveMessages) saveMessages("decoding_ipp_response_${request.requestId}_failed")
232+
if (onExceptionSaveMessages) saveMessages(
233+
fileNameWithoutSuffix = "decoding_ipp_response_${request.requestId}_from_${request.operation}_failed"
234+
)
233235
}
234236
}
235237
}

src/main/kotlin/de/gmuth/ipp/client/IppDocument.kt

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package de.gmuth.ipp.client
22

33
/**
4-
* Copyright (c) 2021-2024 Gerhard Muth
4+
* Copyright (c) 2021-2025 Gerhard Muth
55
*/
66

77
import de.gmuth.ipp.core.IppAttributesGroup
@@ -11,9 +11,14 @@ import java.io.File
1111
import java.io.IOException
1212
import java.io.InputStream
1313
import java.io.OutputStream
14+
import java.nio.file.Files
15+
import java.nio.file.Files.newOutputStream
16+
import java.nio.file.Path
1417
import java.util.logging.Level
1518
import java.util.logging.Logger
1619
import java.util.logging.Logger.getLogger
20+
import kotlin.io.path.createDirectories
21+
import kotlin.io.path.isRegularFile
1722

1823
@Suppress("kotlin:S1192")
1924
class IppDocument(
@@ -30,6 +35,7 @@ class IppDocument(
3035
"text/plain" -> "txt"
3136
else -> mediaType.split("/")[1]
3237
}
38+
3339
fun getDocumentFormatFilenameExtension(attributes: IppAttributesGroup) =
3440
getFilenameExtension(attributes.getValue("document-format"))
3541
}
@@ -45,7 +51,7 @@ class IppDocument(
4551
val name: IppString
4652
get() = attributes.getValue("document-name")
4753

48-
var file: File? = null
54+
var file: Path? = null
4955

5056
fun readBytes() = inputStream.readBytes()
5157
.also { logger.fine { "Read ${it.size} bytes of $this" } }
@@ -71,25 +77,25 @@ class IppDocument(
7177
inputStream.copyTo(outputStream)
7278

7379
fun save(
74-
directory: File = job.printer.printerDirectory,
80+
directory: Path = job.printer.printerDirectory,
7581
filename: String = filename(),
7682
overwrite: Boolean = true
77-
) = File(directory, filename).also {
78-
if (!directory.exists()) directory.mkdirs()
79-
if (it.isFile && !overwrite) throw IOException("File '$it' already exists")
80-
copyTo(it.outputStream())
83+
) = directory.resolve(filename).also {
84+
it.parent?.createDirectories()
85+
if (it.isRegularFile() && !overwrite) throw IOException("File '$it' already exists")
86+
copyTo(newOutputStream(it))
8187
this.file = it
8288
logger.info { "Saved $file ${if (attributes.containsKey("document-format")) "($format)" else ""}" }
8389
}
8490

8591
fun runtimeExecCommand(commandToHandleFile: String) =
8692
if (file == null) throw IppException("Missing file to handle.")
87-
else Runtime.getRuntime().exec(arrayOf(commandToHandleFile, file!!.absolutePath))
93+
else Runtime.getRuntime().exec(arrayOf(commandToHandleFile, file!!.toAbsolutePath().toString()))
8894

8995
override fun toString() = StringBuilder("Document #$number").run {
9096
append(" ($format) of job #${job.id}")
9197
if (attributes.containsKey("document-name")) append(" '$name'")
92-
if (file != null) append(": $file (${file!!.length()} bytes)")
98+
if (file != null) append(": $file (${Files.size(file!!)} bytes)")
9399
toString()
94100
}
95101

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package de.gmuth.ipp.client
22

33
/**
4-
* Copyright (c) 2020-2024 Gerhard Muth
4+
* Copyright (c) 2020-2025 Gerhard Muth
55
*/
66

77
import de.gmuth.ipp.core.IppException
88
import de.gmuth.ipp.core.IppRequest
9-
import java.io.File
9+
import java.nio.file.Path
1010
import java.util.logging.Level
1111
import java.util.logging.Level.INFO
1212
import java.util.logging.Logger
1313
import kotlin.io.path.createTempDirectory
14-
import kotlin.io.path.pathString
1514

1615
open class IppExchangeException(
1716
val request: IppRequest,
@@ -25,10 +24,9 @@ open class IppExchangeException(
2524
}
2625

2726
open fun saveMessages(
28-
fileNameWithoutSuffix: String = "ipp_exchange_exception",
29-
directory: String = createTempDirectory("ipp-client-").pathString
30-
) {
31-
request.saveBytes(File(directory, "$fileNameWithoutSuffix.request"))
32-
}
27+
directory: Path = createTempDirectory("ipp-client-"),
28+
fileNameWithoutSuffix: String = "ipp_exchange_exception"
29+
) =
30+
request.saveBytes(directory.resolve("$fileNameWithoutSuffix.request"))
3331

3432
}

0 commit comments

Comments
 (0)