summaryrefslogtreecommitdiff
path: root/src/main/java/com/amazon/carbonado/adapter/TextAdapter.java
diff options
context:
space:
mode:
authorBrian S. O'Neill <bronee@gmail.com>2006-08-30 01:46:24 +0000
committerBrian S. O'Neill <bronee@gmail.com>2006-08-30 01:46:24 +0000
commit3635740f2fcb24192cfa20a3d8d30cbc690c64d8 (patch)
tree698434cfcadf3752accef6943b101e7743d0f60e /src/main/java/com/amazon/carbonado/adapter/TextAdapter.java
parent2246eac504e5593cdf4a489f97be85e2cc56dcf8 (diff)
Add standard adapters
Diffstat (limited to 'src/main/java/com/amazon/carbonado/adapter/TextAdapter.java')
-rw-r--r--src/main/java/com/amazon/carbonado/adapter/TextAdapter.java244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/main/java/com/amazon/carbonado/adapter/TextAdapter.java b/src/main/java/com/amazon/carbonado/adapter/TextAdapter.java
new file mode 100644
index 0000000..e07ed50
--- /dev/null
+++ b/src/main/java/com/amazon/carbonado/adapter/TextAdapter.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2006 Amazon Technologies, Inc. or its affiliates.
+ * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
+ * of Amazon Technologies, Inc. or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.amazon.carbonado.adapter;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+import com.amazon.carbonado.FetchException;
+import com.amazon.carbonado.PersistException;
+
+import com.amazon.carbonado.lob.Blob;
+import com.amazon.carbonado.lob.ByteArrayBlob;
+import com.amazon.carbonado.lob.Clob;
+import com.amazon.carbonado.lob.StringClob;
+
+import com.amazon.carbonado.adapter.AdapterDefinition;
+
+/**
+ * Converts database Blobs and Clobs to Strings. This is suitable for text
+ * values which are expected to fit entirely in memory. The storage layer will
+ * attempt to store the text as a regular string, but will use a blob type if
+ * required to.
+ *
+ * <p>Example:<pre>
+ * public interface UserInfo extends Storable {
+ * <b>&#64;TextAdapter(charset="UTF-8")</b>
+ * String getWelcomeMessage();
+ *
+ * ...
+ * }
+ * </pre>
+ *
+ * @author Brian S O'Neill
+ * @see Clob
+ * @see Blob
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@AdapterDefinition(storageTypePreferences={
+ String.class,
+ Clob.class,
+ Blob.class
+})
+public @interface TextAdapter {
+ /**
+ * Optionally specify a character set, which is used if the storage type is
+ * a Blob.
+ */
+ String charset() default "UTF-8";
+
+ /**
+ * Optionally specify alternate character sets, which are used if text
+ * cannot be decoded with primary charset.
+ */
+ String[] altCharsets() default {};
+
+ /**
+ * Adapter implementation for {@link TextAdapter}.
+ */
+ public static class Adapter {
+ private static byte[] EMPTY_BYTE_ARRAY = new byte[0];
+
+ static PersistException toPersistException(IOException e) {
+ Throwable cause = e.getCause();
+ if (cause instanceof PersistException) {
+ return (PersistException) cause;
+ }
+ if (cause == null) {
+ cause = e;
+ }
+ return new PersistException(cause);
+ }
+
+ private static final Charset[] prepareAltCharsets(TextAdapter ann) {
+ if (ann == null) {
+ return null;
+ }
+ String[] strs = ann.altCharsets();
+ if (strs == null || strs.length == 0) {
+ return null;
+ }
+ Charset[] altCharsets = new Charset[strs.length];
+ for (int i=0; i<strs.length; i++) {
+ altCharsets[i] = Charset.forName(strs[i]);
+ }
+ return altCharsets;
+ }
+
+ private final Charset mCharset;
+ private final Charset[] mAltCharsets;
+
+ /**
+ * @param type type of object that contains the adapted property
+ * @param propertyName name of property with adapter
+ * @param ann specific annotation that binds to this adapter class
+ */
+ public Adapter(Class<?> type, String propertyName, TextAdapter ann) {
+ this(type, propertyName,
+ (ann == null ? null : Charset.forName(ann.charset())),
+ prepareAltCharsets(ann));
+ }
+
+ /**
+ * @param type type of object that contains the adapted property
+ * @param propertyName name of property with
+ * @param charset character set to use, or null to use default of UTF-8.
+ */
+ public Adapter(Class<?> type, String propertyName, String charset) {
+ this(type, propertyName, charset == null ? null : Charset.forName(charset), null);
+ }
+
+ /**
+ * @param type type of object that contains the adapted property
+ * @param propertyName name of property with
+ * @param charset character set to use, or null to use default of UTF-8.
+ */
+ public Adapter(Class<?> type, String propertyName, Charset charset) {
+ this(type, propertyName, charset, null);
+ }
+
+ /**
+ * @param type type of object that contains the adapted property
+ * @param propertyName name of property with
+ * @param charset character set to use, or null to use default of UTF-8.
+ * @param altCharsets alternate character sets to use, if text cannot be
+ * decoded with primary charset
+ */
+ public Adapter(Class<?> type, String propertyName, Charset charset, Charset[] altCharsets)
+ {
+ mCharset = charset == null ? Charset.forName("UTF-8") : charset;
+ if (altCharsets == null || altCharsets.length == 0) {
+ altCharsets = null;
+ } else {
+ altCharsets = altCharsets.clone();
+ }
+ mAltCharsets = altCharsets;
+ }
+
+ // Adapt to String...
+
+ public String adaptToString(Clob clob) throws FetchException {
+ return clob == null ? null : clob.asString();
+ }
+
+ public String adaptToString(Blob blob) throws FetchException {
+ FetchException error;
+
+ try {
+ return blob == null ? null : blob.asString(mCharset);
+ } catch (FetchException e) {
+ if (mAltCharsets == null) {
+ throw e;
+ }
+ Throwable cause = e.getCause();
+ if (!(cause instanceof CharacterCodingException)) {
+ throw e;
+ }
+ error = e;
+ }
+
+ for (int i=0; i<mAltCharsets.length; i++) {
+ try {
+ return blob.asString(mAltCharsets[i]);
+ } catch (FetchException e) {
+ Throwable cause = e.getCause();
+ if (!(cause instanceof CharacterCodingException)) {
+ throw e;
+ }
+ }
+ }
+
+ throw error;
+ }
+
+ // Adapt from String...
+
+ public Clob adaptToClob(String text) {
+ if (text == null) {
+ return null;
+ }
+ return new StringClob(text);
+ }
+
+ public Blob adaptToBlob(String text) throws PersistException {
+ if (text == null) {
+ return null;
+ }
+
+ if (text.length() == 0) {
+ return new ByteArrayBlob(EMPTY_BYTE_ARRAY);
+ }
+
+ CharsetEncoder encoder = mCharset.newEncoder();
+
+ long byteLength = (long) (text.length() * encoder.averageBytesPerChar());
+
+ if (byteLength >= Integer.MAX_VALUE) {
+ byteLength = Integer.MAX_VALUE;
+ }
+
+ byte[] buffer = new byte[(int) byteLength];
+
+ Blob blob = new ByteArrayBlob(buffer, 0);
+
+ Writer w = new OutputStreamWriter(blob.openOutputStream(), encoder);
+ try {
+ w.write(text, 0, text.length());
+ w.close();
+ } catch (IOException e) {
+ throw toPersistException(e);
+ }
+
+ return blob;
+ }
+ }
+}