All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cayenne.util.MemoryClob Maven / Gradle / Ivy

There is a newer version: 2.0.4
Show newest version
/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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 org.apache.cayenne.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.sql.Clob;
import java.sql.SQLException;

import org.apache.cayenne.CayenneRuntimeException;

/**
 * A Clob implementation that stores contents in memory.
 * 

* This implementation is based on jdbcClob from HSQLDB (copyright HSQL Development * Group). *

* * @since 1.2 * @author Andrus Adamchik */ public class MemoryClob implements Clob { volatile String data; /** * Constructs a new jdbcClob object wrapping the given character sequence. *

* This constructor is used internally to retrieve result set values as Clob objects, * yet it must be public to allow access from other packages. As such (in the interest * of efficiency) this object maintains a reference to the given String object rather * than making a copy and so it is gently suggested (in the interest of effective * memory management) that extenal clients using this constructor either take pause to * consider the implications or at least take care to provide a String object whose * internal character buffer is not much larger than required to represent the value. * * @param data the character sequence representing the Clob value * @throws SQLException if the argument is null */ public MemoryClob(String data) { if (data == null) { throw new CayenneRuntimeException("Null data"); } this.data = data; } /** * Retrieves the number of characters in the CLOB value designated by * this Clob object. * * @return length of the CLOB in characters * @exception SQLException if there is an error accessing the length of the * CLOB value */ public long length() throws SQLException { final String ldata = data; return ldata.length(); } /** * Retrieves a copy of the specified substring in the CLOB value * designated by this Clob object. The substring begins at position * pos and has up to length consecutive characters. */ public String getSubString(long pos, final int length) throws SQLException { final String ldata = data; final int dlen = ldata.length(); pos--; if (pos < 0 || pos > dlen) { new CayenneRuntimeException("Invalid position: " + (pos + 1L)); } if (length < 0 || length > dlen - pos) { throw new CayenneRuntimeException("Invalid length: " + length); } if (pos == 0 && length == dlen) { return ldata; } return ldata.substring((int) pos, (int) pos + length); } /** * Retrieves the CLOB value designated by this Clob * object as a java.io.Reader object (or as a stream of characters). * * @return a java.io.Reader object containing the CLOB * data * @exception SQLException if there is an error accessing the CLOB * value */ public java.io.Reader getCharacterStream() throws SQLException { final String ldata = data; return new StringReader(ldata); } /** * Retrieves the CLOB value designated by this Clob * object as an ascii stream. * * @return a java.io.InputStream object containing the * CLOB data * @exception SQLException if there is an error accessing the CLOB * value */ public java.io.InputStream getAsciiStream() throws SQLException { final String ldata = data; return new AsciiStringInputStream(ldata); } /** * Retrieves the character position at which the specified substring * searchstr appears in the SQL CLOB value represented * by this Clob object. The search begins at position * start. * * @param searchstr the substring for which to search * @param start the position at which to begin searching; the first position is 1 * @return the position at which the substring appears or -1 if it is not present; the * first position is 1 * @exception SQLException if there is an error accessing the CLOB * value */ public long position(final String searchstr, long start) throws SQLException { if (searchstr == null || start > Integer.MAX_VALUE) { return -1; } final String ldata = data; final int pos = ldata.indexOf(searchstr, (int) --start); return (pos < 0) ? -1 : pos + 1; } /** * Retrieves the character position at which the specified Clob object * searchstr appears in this Clob object. The search * begins at position start. * * @param searchstr the Clob object for which to search * @param start the position at which to begin searching; the first position is 1 * @return the position at which the Clob object appears or -1 if it is * not present; the first position is 1 * @exception SQLException if there is an error accessing the CLOB * value */ public long position(final Clob searchstr, long start) throws SQLException { if (searchstr == null) { return -1; } final String ldata = data; final long dlen = ldata.length(); final long sslen = searchstr.length(); // This is potentially much less expensive than materializing a large // substring from some other vendor's CLOB. Indeed, we should probably // do the comparison piecewise, using an in-memory buffer (or temp-files // when available), if it is detected that the input CLOB is very long. if (start > dlen - sslen) { return -1; } // by now, we know sslen and start are both < Integer.MAX_VALUE String s; if (searchstr instanceof MemoryClob) { s = ((MemoryClob) searchstr).data; } else { s = searchstr.getSubString(1L, (int) sslen); } final int pos = ldata.indexOf(s, (int) start); return (pos < 0) ? -1 : pos + 1; } /** * Writes the given Java String to the CLOB value that * this Clob object designates at the position pos. * Calling this method always throws an SQLException. */ public int setString(long pos, String str) throws SQLException { throw new CayenneRuntimeException("Not supported"); } /** * Writes len characters of str, starting at character * offset, to the CLOB value that this * Clob represents. Calling this method always throws an * SQLException. */ public int setString(long pos, String str, int offset, int len) throws SQLException { throw new CayenneRuntimeException("Not supported"); } /** * Retrieves a stream to be used to write Ascii characters to the CLOB * value that this Clob object represents, starting at position * pos. *

* Calling this method always throws an SQLException. */ public java.io.OutputStream setAsciiStream(long pos) throws SQLException { throw new CayenneRuntimeException("Not supported"); } /** * Retrieves a stream to be used to write a stream of Unicode characters to the * CLOB value that this Clob object represents, at * position pos. *

* Calling this method always throws an SQLException. */ public java.io.Writer setCharacterStream(long pos) throws SQLException { throw new CayenneRuntimeException("Not supported"); } /** * Truncates the CLOB value that this Clob designates to * have a length of len characters. *

*/ public void truncate(final long len) throws SQLException { final String ldata = data; final long dlen = ldata.length(); final long chars = len >> 1; if (chars == dlen) { // nothing has changed, so there's nothing to be done } else if (len < 0 || chars > dlen) { throw new CayenneRuntimeException("Invalid length: " + len); } else { // use new String() to ensure we get rid of slack data = new String(ldata.substring(0, (int) chars)); } } class AsciiStringInputStream extends InputStream { protected int strOffset = 0; protected int charOffset = 0; protected int available; protected String str; public AsciiStringInputStream(String s) { str = s; available = s.length() * 2; } public int doRead() throws IOException { if (available == 0) { return -1; } available--; char c = str.charAt(strOffset); if (charOffset == 0) { charOffset = 1; return (c & 0x0000ff00) >> 8; } else { charOffset = 0; strOffset++; return c & 0x000000ff; } } public int read() throws IOException { doRead(); return doRead(); } public int available() throws IOException { return available / 2; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy