in api/applib/src/main/java/org/apache/causeway/applib/value/Clob.java [76:343]
public record Clob(
String name,
MimeType mimeType,
CharSequence chars
) implements NamedWithMimeType {
// -- FACTORIES
/**
* Returns a new {@link Clob} of given {@code name}, {@code mimeType} and {@code content}.
* <p>
* {@code name} may or may not include the desired filename extension, as it
* is guaranteed, that the resulting {@link Clob} has the appropriate extension
* as constraint by the given {@code mimeType}.
* <p>
* For more fine-grained control use one of the {@link Clob} constructors directly.
* @param name - may or may not include the desired filename extension
* @param mimeType
* @param content - chars
* @return new {@link Clob}
*/
public static Clob of(final String name, final CommonMimeType mimeType, final CharSequence content) {
var fileName = _Strings.asFileNameWithExtension(name, mimeType.getProposedFileExtensions());
return new Clob(fileName, mimeType.getMimeType(), content);
}
/**
* Returns a new {@link Clob} of given {@code name}, {@code mimeType} and content from {@code dataSource},
* wrapped with a {@link Try}.
* <p>
* {@code name} may or may not include the desired filename extension, as it
* is guaranteed, that the resulting {@link Clob} has the appropriate extension
* as constraint by the given {@code mimeType}.
* <p>
* For more fine-grained control use one of the {@link Clob} constructors directly.
* @param name - may or may not include the desired filename extension
* @param mimeType
* @param dataSource - the {@link DataSource} to be opened for reading
* @param charset - {@link Charset} to use for reading from given {@link DataSource}
* @return new {@link Clob}
*/
public static Try<Clob> tryRead(final String name, final CommonMimeType mimeType, final DataSource dataSource,
final @NonNull Charset charset) {
return dataSource.tryReadAsString(charset)
.mapSuccess(string->Clob.of(name, mimeType, string.orElse(null)));
}
/**
* Shortcut for {@code tryRead(name, mimeType, DataSource.ofFile(file), charset)}
* @see #tryRead(String, org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType, DataSource, Charset)
*/
public static Try<Clob> tryRead(final String name, final CommonMimeType mimeType, final File file,
final @NonNull Charset charset) {
return tryRead(name, mimeType, DataSource.ofFile(file), charset);
}
/**
* Shortcut for {@link #tryRead(String, org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType, File, Charset)}
* using {@link StandardCharsets#UTF_8}.
*/
public static Try<Clob> tryReadUtf8(final String name, final CommonMimeType mimeType, final File file) {
return tryRead(name, mimeType, file, StandardCharsets.UTF_8);
}
// --
public Clob(final String name, final String primaryType, final String subType, final char[] chars) {
this(name, primaryType, subType, new String(chars));
}
public Clob(final String name, final String mimeTypeBase, final char[] chars) {
this(name, mimeTypeBase, new String(chars));
}
public Clob(final String name, final MimeType mimeType, final char[] chars) {
this(name, mimeType, new String(chars));
}
public Clob(final String name, final String primaryType, final String subType, final CharSequence chars) {
this(name, CommonMimeType.newMimeType(primaryType, subType), chars);
}
public Clob(final String name, final String mimeTypeBase, final CharSequence chars) {
this(name, CommonMimeType.newMimeType(mimeTypeBase), chars);
}
// canonical constructor
public Clob(final String name, final MimeType mimeType, final CharSequence chars) {
if(name == null) {
throw new IllegalArgumentException("Name cannot be null");
}
if(mimeType == null) {
throw new IllegalArgumentException("MimeType cannot be null");
}
if(name.contains(":")) {
throw new IllegalArgumentException("Name cannot contain ':'");
}
if(chars == null) {
throw new IllegalArgumentException("Chars cannot be null");
}
this.name = name;
this.mimeType = mimeType;
this.chars = chars;
}
/**
* @deprecated use {@link #chars()} instead
*/
public CharSequence getChars() { return chars(); }
// -- UTILITIES
/**
* Converts to a {@link Blob}, using given {@link Charset}
* for the underlying String to byte[] conversion.
*/
public Blob toBlob(final @NonNull Charset charset) {
return new Blob(name(), mimeType(), _Strings.toBytes(chars().toString(), charset));
}
/**
* Shortcut for {@link #toBlob(Charset)} using {@link StandardCharsets#UTF_8}.
*/
public Blob toBlobUtf8() {
return toBlob(StandardCharsets.UTF_8);
}
public void writeCharsTo(final Writer wr) throws IOException {
if(wr!=null && chars!=null){
wr.append(chars);
}
}
/**
* Writes this {@link Clob} to the file represented by
* the specified <code>File</code> object.
* <p>
* If the file exists but is a directory rather than a regular file, does
* not exist but cannot be created, or cannot be opened for any other
* reason then a <code>FileNotFoundException</code> is thrown.
*
* @param file the file to be opened for writing; if <code>null</code> this method does nothing
* @param charset - {@link Charset} to use for writing to given file
* @see java.io.FileOutputStream
* @see java.io.OutputStreamWriter
*/
@SneakyThrows
public void writeTo(final @Nullable File file, final @NonNull Charset charset) {
if(file==null) {
return; // just ignore
}
try(var os = new OutputStreamWriter(new FileOutputStream(file), charset)){
writeCharsTo(os);
}
}
/**
* Shortcut for {@link #writeTo(File, Charset)} using {@link StandardCharsets#UTF_8}.
*/
public void writeToUtf8(final @Nullable File file) {
writeTo(file, StandardCharsets.UTF_8);
}
@SneakyThrows
public String asString() {
var sw = new StringWriter();
writeCharsTo(sw);
return sw.toString();
}
// -- OBJECT CONTRACT
@Override
public boolean equals(final Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
final Clob clob = (Clob) o;
return Objects.equals(name, clob.name) &&
Objects.equals(mimeType.toString(), clob.mimeType.toString()) &&
Objects.equals(chars, clob.chars);
}
@Override public int hashCode() {
return Objects.hash(name, mimeType.toString(), chars);
}
@Override
public String toString() {
return name() + " [" + mimeType().getBaseType() + "]: " + getChars().length() + " chars";
}
/**
* (thread-safe)
* @implNote see also ClobValueSemanticsProvider
*/
public static final class JaxbToStringAdapter extends XmlAdapter<String, Clob> {
private final PrimitiveJaxbAdapters.BytesAdapter bytesAdapter = new PrimitiveJaxbAdapters.BytesAdapter(); // thread-safe
@Override
public Clob unmarshal(final String data) throws Exception {
if(data==null) {
return null;
}
final int colonIdx = data.indexOf(':');
final String name = data.substring(0, colonIdx);
final int colon2Idx = data.indexOf(":", colonIdx+1);
final String mimeTypeBase = data.substring(colonIdx+1, colon2Idx);
final String payload = data.substring(colon2Idx+1);
final byte[] bytes = bytesAdapter.unmarshal(payload);
try {
return new Clob(name, new MimeType(mimeTypeBase), new String(bytes, StandardCharsets.UTF_8));
} catch (MimeTypeParseException e) {
throw new RuntimeException(e);
}
}
@Override
public String marshal(final Clob clob) throws Exception {
if(clob==null) {
return null;
}
return new StringBuilder()
.append(clob.name())
.append(':')
.append(clob.mimeType().getBaseType())
.append(':')
.append(bytesAdapter.marshal(clob.chars().toString().getBytes(StandardCharsets.UTF_8)))
.toString();
}
}
// -- SERIALIZATION PROXY
private Object writeReplace() {
return new SerializationProxy(this);
}
private void readObject(final ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
private static class SerializationProxy implements Serializable {
/**
* Generated, based on String, String, CharSequence
*/
private static final long serialVersionUID = -3598440606899920566L;
private final String name;
private final String mimeTypeBase;
private final CharSequence chars;
private SerializationProxy(final Clob clob) {
this.name = clob.name();
this.mimeTypeBase = clob.mimeType().getBaseType();
this.chars = clob.chars();
}
private Object readResolve() {
return new Clob(name, mimeTypeBase, chars);
}
}
}