1 16 package org.apache.cocoon.components.source.impl; 17 18 import java.io.ByteArrayInputStream ; 19 import java.io.FilterInputStream ; 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.net.MalformedURLException ; 23 import java.sql.Blob ; 24 import java.sql.Clob ; 25 import java.sql.Connection ; 26 import java.sql.ResultSet ; 27 import java.sql.SQLException ; 28 import java.sql.Statement ; 29 import java.sql.Types ; 30 import java.util.Iterator ; 31 32 import org.apache.avalon.framework.logger.AbstractLogEnabled; 33 import org.apache.avalon.framework.service.ServiceManager; 34 import org.apache.avalon.framework.service.ServiceSelector; 35 import org.apache.avalon.framework.service.Serviceable; 36 37 import org.apache.avalon.excalibur.datasource.DataSourceComponent; 38 39 import org.apache.cocoon.CascadingIOException; 40 41 import org.apache.excalibur.source.Source; 42 import org.apache.excalibur.source.SourceException; 43 import org.apache.excalibur.source.SourceValidity; 44 45 65 public class BlobSource extends AbstractLogEnabled implements Source, Serviceable { 66 67 68 private ServiceManager manager = null; 69 70 73 private String systemId; 74 75 private String datasourceName; 76 77 private String tableName; 78 79 private String columnName; 80 81 private String condition; 82 83 private final static String URL_PREFIX = "blob:/"; 84 private final static int URL_PREFIX_LEN = URL_PREFIX.length(); 85 86 90 public BlobSource(String url) throws MalformedURLException { 91 92 this.systemId = url; 93 94 int start = URL_PREFIX_LEN; 96 int end; 97 98 end = url.indexOf('/', start); 100 if (end == -1) { 101 throw new MalformedURLException ("Malformed blob source (cannot find datasource) : " + url); 102 } 103 104 this.datasourceName = url.substring(start, end); 105 106 start = end + 1; 108 end = url.indexOf('/', start); 109 if (end == -1) { 110 throw new MalformedURLException ("Malformed blob source (cannot find table name) : " + url); 111 } 112 113 this.tableName = url.substring(start, end); 114 115 start = end + 1; 117 end = url.indexOf('[', start); 118 if (end == -1) { 119 this.columnName = url.substring(start); 120 } else { 121 this.columnName = url.substring(start, end); 122 123 start = end + 1; 125 end = url.length() - 1; 126 if (url.charAt(end) != ']') { 127 throw new MalformedURLException ("Malformed url for a blob source (cannot find condition) : " + url); 128 } else { 129 this.condition = url.substring(start, end); 130 } 131 } 132 } 133 134 138 public void service(ServiceManager manager) { 139 this.manager = manager; 140 } 141 142 145 public String getScheme() { 146 return URL_PREFIX; 147 } 148 149 152 public String getURI() { 153 return this.systemId; 154 } 155 156 159 public InputStream getInputStream() throws IOException , SourceException { 160 if (getLogger().isDebugEnabled()) { 161 getLogger().debug("Opening stream for datasource " + this.datasourceName + 162 ", table " + this.tableName + ", column " + this.columnName + 163 (this.condition == null ? ", no condition" : ", condition " + this.condition) 164 ); 165 } 166 167 Connection cnx = null; 168 Statement stmt = null; 169 170 try { 171 cnx = getConnection(); 172 stmt = cnx.createStatement(); 173 174 StringBuffer selectBuf = new StringBuffer ("SELECT ").append(this.columnName). 175 append(" FROM ").append(this.tableName); 176 177 if (this.condition != null) { 178 selectBuf.append(" WHERE ").append(this.condition); 179 } 180 181 String select = selectBuf.toString(); 182 if (getLogger().isDebugEnabled()) { 183 getLogger().debug("Executing statement " + select); 184 } 185 186 ResultSet rs = stmt.executeQuery(select); 187 rs.next(); 188 189 int colType = rs.getMetaData().getColumnType(1); 190 191 switch(colType) { 192 case Types.BLOB : 193 Blob blob = rs.getBlob(1); 194 return new JDBCInputStream(blob.getBinaryStream(), cnx); 195 197 case Types.CLOB : 198 Clob clob = rs.getClob(1); 199 return new JDBCInputStream(clob.getAsciiStream(), cnx); 200 202 default : 203 String value = rs.getString(1); 204 return new ByteArrayInputStream (value.getBytes()); 205 } 206 } catch(SQLException sqle) { 207 String msg = "Cannot retrieve content from " + this.systemId; 208 getLogger().error(msg, sqle); 209 throw new SourceException(msg, sqle); 211 } finally { 212 try { 213 if (stmt != null) { 214 stmt.close(); 215 } 216 if (cnx != null) { 217 cnx.close(); 218 } 219 } catch(SQLException sqle2) { 220 throw new SourceException("Cannot close connection", sqle2); 222 } 223 } 224 } 225 226 232 public SourceValidity getValidity() { 233 return null; 234 } 235 236 240 public void refresh() { 241 } 242 243 247 public boolean exists() { 248 return true; 250 } 251 252 257 public String getMimeType() { 258 return null; 259 } 260 261 265 public long getContentLength() { 266 return -1; 267 } 268 269 274 public long getLastModified() { 275 return 0; 276 } 277 278 283 public String getParameter(String name) { 284 return null; 285 } 286 287 292 public long getParameterAsLong(String name) { 293 return 0; 294 } 295 296 301 public Iterator getParameterNames() { 302 return new EmptyIterator(); 303 } 304 305 static class EmptyIterator implements Iterator { 306 public boolean hasNext() { return false; } 307 public Object next() { return null; } 308 public void remove() {} 309 } 310 311 private Connection getConnection() throws SourceException { 312 313 ServiceSelector selector = null; 314 DataSourceComponent datasource = null; 315 316 try { 317 try { 318 selector = (ServiceSelector)this.manager.lookup(DataSourceComponent.ROLE + "Selector"); 319 320 datasource = (DataSourceComponent)selector.select(this.datasourceName); 321 322 } catch(Exception e) { 323 String msg = "Cannot get datasource '" + this.datasourceName + "'"; 324 getLogger().error(msg); 325 throw new SourceException(msg, e); 326 } 327 328 try { 329 return datasource.getConnection(); 330 } catch(Exception e) { 331 String msg = "Cannot get connection for datasource '" + this .datasourceName + "'"; 332 getLogger().error(msg); 333 throw new SourceException(msg, e); 334 } 335 336 } finally { 337 if (datasource != null) { 338 selector.release(datasource); 339 } 340 } 341 } 342 343 347 private class JDBCInputStream extends FilterInputStream { 348 349 Connection cnx; 350 351 private final void closeCnx() throws IOException { 352 if (this.cnx != null) { 353 try { 354 Connection tmp = cnx; 355 cnx = null; 356 tmp.close(); 357 } catch(Exception e) { 358 String msg = "Error closing the connection for " + BlobSource.this.getURI(); 359 BlobSource.this.getLogger().warn(msg, e); 360 throw new CascadingIOException(msg + " : " + e.getMessage(), e); 361 } 362 } 363 } 364 365 public JDBCInputStream(InputStream stream, Connection cnx) { 366 super(stream); 367 this.cnx = cnx; 368 } 369 370 public int read() throws IOException { 371 try { 372 int result = in.read(); 373 if (result == -1) { 374 closeCnx(); 375 } 376 return result; 377 } catch(IOException e) { 378 closeCnx(); 379 throw e; 380 } 381 } 382 383 public int read(byte[] b) throws IOException { 384 try { 385 int result = in.read(b); 386 if (result == -1) { 387 closeCnx(); 388 } 389 return result; 390 } catch(IOException e) { 391 closeCnx(); 392 throw e; 393 } 394 } 395 396 public int read(byte[] b, int off, int len) throws IOException { 397 try { 398 int result = in.read(b, off, len); 399 if (result == -1) { 400 closeCnx(); 401 } 402 return result; 403 } catch(IOException e) { 404 closeCnx(); 405 throw e; 406 } 407 } 408 409 public void close() throws IOException { 410 super.close(); 411 closeCnx(); 412 } 413 } 414 } 415 416 | Popular Tags |