BrightSide Workbench Full Report + Source Code
ClobProxy_360.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2011 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 package org.hibernate.engine.jdbc;
19 
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.Reader;
23 import java.io.StringReader;
24 import java.lang.reflect.InvocationHandler;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Proxy;
27 import java.sql.Clob;
28 import java.sql.SQLException;
29 import org.hibernate.type.descriptor.java.DataHelper;
30 
39 public class ClobProxy_360 implements InvocationHandler {
40  private static final Class[] PROXY_INTERFACES = new Class[] { Clob.class, ClobImplementer.class };
41 
42  private String string;
43  private Reader reader;
44  private long length;
45  private boolean needsReset = false;
46 
47 
54  protected ClobProxy_360(String string) {
55  this.string = string;
56  reader = new StringReader(string);
57  length = string.length();
58  }
59 
67  protected ClobProxy_360(Reader reader, long length) {
68  this.reader = reader;
69  this.length = length;
70  }
71 
72  protected long getLength() {
73  return length;
74  }
75 
76  protected InputStream getAsciiStream() throws SQLException {
77  resetIfNeeded();
78  return new ReaderInputStream( reader );
79  }
80 
81  protected Reader getCharacterStream() throws SQLException {
82  resetIfNeeded();
83  return reader;
84  }
85 
86  protected String getSubString(long start, int length) {
87  if ( string == null ) {
88  throw new UnsupportedOperationException( "Clob was not created from string; cannot substring" );
89  }
90  // semi-naive implementation
91  int endIndex = Math.min( ((int)start)+length, string.length() );
92  return string.substring( (int)start, endIndex );
93  }
94 
101  @SuppressWarnings({ "UnnecessaryBoxing" })
102  @Override
103  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
104  final String methodName = method.getName();
105  final int argCount = method.getParameterTypes().length;
106 
107  if ( "length".equals( methodName ) && argCount == 0 ) {
108  return Long.valueOf( getLength() );
109  }
110  if ( "getAsciiStream".equals( methodName ) && argCount == 0 ) {
111  return getAsciiStream();
112  }
113  if ( "getCharacterStream".equals( methodName ) ) {
114  if ( argCount == 0 ) {
115  return getCharacterStream();
116  }
117  else if ( argCount == 2 ) {
118  long start = (Long) args[0];
119  if ( start < 1 ) {
120  throw new SQLException( "Start position 1-based; must be 1 or more." );
121  }
122  if ( start > getLength() ) {
123  throw new SQLException( "Start position [" + start + "] cannot exceed overall CLOB length [" + getLength() + "]" );
124  }
125  int length = (Integer) args[1];
126  if ( length < 0 ) {
127  // java docs specifically say for getCharacterStream(long,int) that the start+length must not exceed the
128  // total length, however that is at odds with the getSubString(long,int) behavior.
129  throw new SQLException( "Length must be great-than-or-equal to zero." );
130  }
131  return DataHelper.subStream( getCharacterStream(), start-1, length );
132  }
133  }
134  if ( "getSubString".equals( methodName ) && argCount == 2 ) {
135  long start = (Long) args[0];
136  if ( start < 1 ) {
137  throw new SQLException( "Start position 1-based; must be 1 or more." );
138  }
139  // from start to start -1 on buggy 3.6.0
140  if ( start - 1 > getLength() ) {
141  throw new SQLException( "Start position [" + start + "] cannot exceed overall CLOB length [" + getLength() + "]" );
142  }
143  int length = (Integer) args[1];
144  if ( length < 0 ) {
145  throw new SQLException( "Length must be great-than-or-equal to zero." );
146  }
147  return getSubString( start-1, length );
148  }
149  if ( "free".equals( methodName ) && argCount == 0 ) {
150  reader.close();
151  return null;
152  }
153  if ( "toString".equals( methodName ) && argCount == 0 ) {
154  return this.toString();
155  }
156  if ( "equals".equals( methodName ) && argCount == 1 ) {
157  return Boolean.valueOf( proxy == args[0] );
158  }
159  if ( "hashCode".equals( methodName ) && argCount == 0 ) {
160  return new Integer( this.hashCode() );
161  }
162 
163  throw new UnsupportedOperationException( "Clob may not be manipulated from creating session" );
164  }
165 
166  protected void resetIfNeeded() throws SQLException {
167  try {
168  if ( needsReset ) {
169  reader.reset();
170  }
171  }
172  catch ( IOException ioe ) {
173  throw new SQLException( "could not reset reader" );
174  }
175  needsReset = true;
176  }
177 
185  public static Clob generateProxy(String string) {
186  return ( Clob ) Proxy.newProxyInstance(getProxyClassLoader(),
187  PROXY_INTERFACES,
188  new ClobProxy_360( string )
189  );
190  }
191 
200  public static Clob generateProxy(Reader reader, long length) {
201  return ( Clob ) Proxy.newProxyInstance(getProxyClassLoader(),
202  PROXY_INTERFACES,
203  new ClobProxy_360( reader, length )
204  );
205  }
206 
213  protected static ClassLoader getProxyClassLoader() {
214  ClassLoader cl = Thread.currentThread().getContextClassLoader();
215  if ( cl == null ) {
216  cl = ClobImplementer.class.getClassLoader();
217  }
218  return cl;
219  }
220 }
static Clob generateProxy(String string)
static Clob generateProxy(Reader reader, long length)
Object invoke(Object proxy, Method method, Object[] args)
ClobProxy_360(Reader reader, long length)
String getSubString(long start, int length)