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

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

There is a newer version: 1.2.4
Show newest version
/* ====================================================================
 * 
 * The ObjectStyle Group Software License, version 1.1
 * ObjectStyle Group - http://objectstyle.org/
 * 
 * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
 * of the software. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if any,
 *    must include the following acknowlegement:
 *    "This product includes software developed by independent contributors
 *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
 *    or promote products derived from this software without prior written
 *    permission. For written permission, email
 *    "andrus at objectstyle dot org".
 * 
 * 5. Products derived from this software may not be called "ObjectStyle"
 *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
 *    names without prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals and hosted on ObjectStyle Group web site.  For more
 * information on the ObjectStyle Group, please see
 * .
 */
package org.objectstyle.cayenne.util;

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

import org.objectstyle.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 - 2025 Weber Informatics LLC | Privacy Policy