From 444b02cff09965abe3719974fbf54e0ba4ebe7c2 Mon Sep 17 00:00:00 2001 From: Julian Reschke Date: Fri, 10 Oct 2025 18:40:28 +0100 Subject: [PATCH] OAK-11979: Clean up *StringValue in JCR XML import --- .../oak/jcr/xml/BufferedStringValue.java | 79 +++---------------- .../jackrabbit/oak/jcr/xml/StringValue.java | 11 +-- 2 files changed, 17 insertions(+), 73 deletions(-) diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/BufferedStringValue.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/BufferedStringValue.java index adeca9fb455..789be161639 100644 --- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/BufferedStringValue.java +++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/BufferedStringValue.java @@ -19,7 +19,6 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -31,15 +30,17 @@ import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.Base64; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.ValueFactory; +import org.apache.commons.io.input.ReaderInputStream; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.spi.xml.TextValue; -import org.apache.jackrabbit.util.Base64; import org.apache.jackrabbit.util.TransientFileFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -133,9 +134,7 @@ public String getString() { private String retrieveString() throws IOException { String value = retrieve(); if (base64) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - Base64.decode(value, out); - value = new String(out.toByteArray(), "UTF-8"); + value = new String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8); } return value; } @@ -157,14 +156,11 @@ public String retrieve() throws IOException { } StringBuilder sb = new StringBuilder((int) length); char[] chunk = new char[0x2000]; - Reader reader = openReader(); - try { + try (Reader reader = openReader()) { int read; while ((read = reader.read(chunk)) > -1) { sb.append(chunk, 0, read); } - } finally { - reader.close(); } return sb.toString(); } else { @@ -173,7 +169,7 @@ public String retrieve() throws IOException { } private Reader openReader() throws IOException { - return new InputStreamReader(openStream(), "UTF-8"); + return new InputStreamReader(openStream(), StandardCharsets.UTF_8); } private InputStream openStream() throws IOException { @@ -182,9 +178,10 @@ private InputStream openStream() throws IOException { private InputStream stream() throws IOException { if (base64) { - return new Base64ReaderInputStream(reader()); + return Base64.getDecoder().wrap( + ReaderInputStream.builder().setReader(reader()).setCharset(StandardCharsets.UTF_8).get()); } else if (buffer != null) { - return new ByteArrayInputStream(retrieve().getBytes("UTF-8")); + return new ByteArrayInputStream(retrieve().getBytes(StandardCharsets.UTF_8)); } else if (tmpFile != null) { // close writer first writer.close(); @@ -229,7 +226,7 @@ public void append(char[] chars, int start, int len) TransientFileFactory fileFactory = TransientFileFactory.getInstance(); tmpFile = fileFactory.createTransientFile("txt", null, null); BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(tmpFile)); - writer = new OutputStreamWriter(fout, "UTF-8"); + writer = new OutputStreamWriter(fout, StandardCharsets.UTF_8); writer.write(buffer.toString()); writer.write(chars, start, len); // reset the in-memory buffer @@ -290,7 +287,9 @@ public void dispose() { } else if (tmpFile != null) { try { writer.close(); - tmpFile.delete(); + if (!tmpFile.delete()) { + log.warn("Problem disposing property value: {} not deleted", tmpFile); + } tmpFile = null; writer = null; } catch (IOException e) { @@ -300,56 +299,4 @@ public void dispose() { log.warn("this instance has already been disposed"); } } - - /** - * This class converts the text read Converts a base64 reader to an input stream. - */ - private static class Base64ReaderInputStream extends InputStream { - - private static final int BUFFER_SIZE = 1024; - private final char[] chars; - private final ByteArrayOutputStream out; - private final Reader reader; - private int pos; - private int remaining; - private byte[] buffer; - - public Base64ReaderInputStream(Reader reader) { - chars = new char[BUFFER_SIZE]; - this.reader = reader; - out = new ByteArrayOutputStream(BUFFER_SIZE); - } - - private void fillBuffer() throws IOException { - int len = reader.read(chars, 0, BUFFER_SIZE); - if (len < 0) { - remaining = -1; - return; - } - Base64.decode(chars, 0, len, out); - buffer = out.toByteArray(); - pos = 0; - remaining = buffer.length; - out.reset(); - } - - @Override - public int read() throws IOException { - if (remaining == 0) { - fillBuffer(); - } - if (remaining < 0) { - return -1; - } - remaining--; - return buffer[pos++] & 0xff; - } - - @Override - public void close() throws IOException { - reader.close(); - } - - } - } diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/StringValue.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/StringValue.java index 553f3f9517e..b933e719e14 100644 --- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/StringValue.java +++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/StringValue.java @@ -17,8 +17,7 @@ package org.apache.jackrabbit.oak.jcr.xml; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; +import java.util.Base64; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; @@ -27,7 +26,6 @@ import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.spi.xml.TextValue; -import org.apache.jackrabbit.util.Base64; /** * {@code StringValue} represents an immutable serialized value. @@ -63,12 +61,11 @@ public String getString() { @Override @SuppressWarnings("deprecation") public Value getValue(int type) throws RepositoryException { if (type == PropertyType.BINARY) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { - Base64.decode(value, baos); + byte[] bytes = Base64.getDecoder().decode(value); return valueFactory.createValue( - new ByteArrayInputStream(baos.toByteArray())); - } catch (IOException e) { + new ByteArrayInputStream(bytes)); + } catch (IllegalArgumentException e) { throw new RepositoryException( "Failed to decode binary value: " + value, e); }