1 16 package org.apache.cocoon.reading; 17 18 import java.io.BufferedInputStream ; 19 import java.io.IOException ; 20 import java.io.InputStream ; 21 import java.sql.Connection ; 22 import java.sql.PreparedStatement ; 23 import java.sql.ResultSet ; 24 import java.sql.SQLException ; 25 import java.sql.Timestamp ; 26 import java.util.Map ; 27 28 import org.apache.avalon.excalibur.datasource.DataSourceComponent; 29 import org.apache.avalon.framework.activity.Disposable; 30 import org.apache.avalon.framework.configuration.Configurable; 31 import org.apache.avalon.framework.configuration.Configuration; 32 import org.apache.avalon.framework.configuration.ConfigurationException; 33 import org.apache.avalon.framework.parameters.Parameters; 34 import org.apache.avalon.framework.service.ServiceException; 35 import org.apache.avalon.framework.service.ServiceManager; 36 import org.apache.avalon.framework.service.ServiceSelector; 37 import org.apache.cocoon.ProcessingException; 38 import org.apache.cocoon.ResourceNotFoundException; 39 import org.apache.cocoon.caching.CacheableProcessingComponent; 40 import org.apache.cocoon.environment.ObjectModelHelper; 41 import org.apache.cocoon.environment.Request; 42 import org.apache.cocoon.environment.Response; 43 import org.apache.cocoon.environment.SourceResolver; 44 import org.apache.excalibur.source.SourceValidity; 45 import org.apache.excalibur.source.impl.validity.NOPValidity; 46 import org.apache.excalibur.source.impl.validity.TimeStampValidity; 47 import org.xml.sax.SAXException ; 48 49 57 public class DatabaseReader extends ServiceableReader 58 implements Configurable, Disposable, CacheableProcessingComponent 59 { 60 61 private ServiceSelector dbselector; 62 private String dsn; 63 private long lastModified = System.currentTimeMillis(); 64 private InputStream resource = null; private Connection con = null; 66 private DataSourceComponent datasource = null; 67 private String mimeType = null; 68 private int typeColumn = 0; 69 private boolean doCommit = false; 70 private boolean defaultCache = true; 71 72 public void service(final ServiceManager manager) throws ServiceException { 73 super.service(manager); 74 this.dbselector = (ServiceSelector) manager.lookup(DataSourceComponent.ROLE + "Selector"); 75 } 76 77 81 public void configure(Configuration conf) throws ConfigurationException { 82 this.dsn = conf.getChild("use-connection").getValue(); 83 this.defaultCache = conf.getChild("invalidate").getValue("never").equals("always"); 84 } 85 86 90 public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) 91 throws ProcessingException, SAXException , IOException { 92 super.setup(resolver, objectModel, src, par); 93 94 PreparedStatement statement = null; 95 try { 96 this.datasource = (DataSourceComponent) dbselector.select(dsn); 97 this.con = datasource.getConnection(); 98 99 if (this.con.getAutoCommit()) { 100 this.con.setAutoCommit(false); 101 } 102 103 statement = con.prepareStatement(getQuery()); 104 statement.setString(1, this.source); 105 ResultSet set = statement.executeQuery(); 106 if (!set.next()) throw new ResourceNotFoundException("There is no resource with that key"); 107 108 Response response = ObjectModelHelper.getResponse(objectModel); 109 Request request = ObjectModelHelper.getRequest(objectModel); 110 111 if (this.modifiedSince(set, request, response)) { 112 this.resource = set.getBinaryStream(1); 113 if (this.typeColumn != 0) { 114 this.mimeType = set.getString(this.typeColumn); 115 } 116 117 if (this.resource == null) { 118 throw new ResourceNotFoundException("There is no resource with that key"); 119 } 120 } 121 122 this.doCommit = true; 123 } catch (Exception e) { 124 this.doCommit = false; 125 throw new ResourceNotFoundException("DatabaseReader error:", e); 126 } finally { 127 try { 128 if (statement != null) { 129 statement.close(); 130 } 131 } catch(SQLException sqle) { 132 throw new ResourceNotFoundException("Cannot close connection", sqle); 133 } 134 } 135 } 136 137 166 public void generate() throws ProcessingException, SAXException , IOException { 167 try { 168 Response response = ObjectModelHelper.getResponse(objectModel); 169 this.serialize(response); 170 } catch (IOException ioe) { 171 getLogger().warn("Assuming client reset stream"); 172 173 this.doCommit = false; 174 } catch (Exception e) { 175 this.doCommit = false; 176 177 throw new ResourceNotFoundException("DatabaseReader error:", e); 178 } 179 } 180 181 186 public String getQuery() throws Exception { 187 String table = this.parameters.getParameter("table", null); 188 String column = this.parameters.getParameter("image", null); 189 String key = this.parameters.getParameter("key", null); 190 String where = this.parameters.getParameter("where", null); 191 String orderBy = this.parameters.getParameter("order-by", null); 192 String typeColumn = this.parameters.getParameter("type-column", null); 193 int columnNo = 1; 194 195 if (table == null || column == null || key==null) { 196 throw new ProcessingException("We are missing a required parameter. Please include 'table', 'image', and 'key'"); 197 } 198 199 String date = this.parameters.getParameter("last-modified", null); 200 StringBuffer query = new StringBuffer ("SELECT "); 201 202 query.append(column); 203 columnNo++; 204 205 if (date != null) { 206 query.append(", ").append(date); 207 columnNo++; 208 } 209 210 if (null != orderBy) { 211 query.append(", "); 212 213 if (orderBy.endsWith(" DESC")) { 214 query.append(orderBy.substring(0, orderBy.length() - 5)); 215 } else { 216 query.append(orderBy); 217 } 218 columnNo++; 219 } 220 221 if (null != typeColumn) { 222 query.append(", ").append(typeColumn); 223 this.typeColumn = columnNo; 224 columnNo++; 225 } 226 227 query.append(" FROM ").append(table); 228 query.append(" WHERE ").append(key).append(" = ?"); 229 230 if (null != where) { 231 query.append(" AND ").append(where); 232 } 233 234 if (null != orderBy) { 235 query.append(" ORDER BY ").append(orderBy); 236 } 237 238 return query.toString(); 239 } 240 241 253 public boolean modifiedSince(ResultSet set, Request request, Response response) 254 throws SQLException { 255 String lastModified = this.parameters.getParameter("last-modified", null); 256 257 if (lastModified != null) { 258 Timestamp modified = set.getTimestamp(lastModified, null); 259 if (null != modified) { 260 this.lastModified = modified.getTime(); 261 } else { 262 } 264 265 response.setDateHeader("Last-Modified", this.lastModified); 266 267 return this.lastModified > request.getDateHeader("if-modified-since"); 268 } 269 270 return true; 273 } 274 275 278 public void serialize(Response response) 279 throws IOException , SQLException { 280 if (this.resource == null) { 281 throw new SQLException ("The Blob is empty!"); 282 } 283 284 InputStream is = new BufferedInputStream (this.resource); 285 286 long expires = parameters.getParameterAsInteger("expires", -1); 287 288 if (expires > 0) { 289 response.setDateHeader("Expires", System.currentTimeMillis() + expires); 290 } 291 292 response.setHeader("Accept-Ranges", "bytes"); 293 294 byte[] buffer = new byte[8192]; 295 int length = -1; 296 297 while ((length = is.read(buffer)) > -1) { 298 out.write(buffer, 0, length); 299 } 300 is.close(); 301 out.flush(); 302 } 303 304 310 public java.io.Serializable getKey() { 311 return this.source; 312 } 313 314 320 public SourceValidity getValidity() { 321 if (this.lastModified > 0) { 322 return new TimeStampValidity(this.lastModified); 323 } else { 324 if (this.defaultCache) { 325 return NOPValidity.SHARED_INSTANCE; 326 } else { 327 return null; 328 } 329 } 330 } 331 332 public void recycle() { 333 super.recycle(); 334 this.resource = null; 335 this.lastModified = 0; 336 this.mimeType = null; 337 this.typeColumn = 0; 338 339 if (this.con != null) { 340 try { 341 if (this.doCommit) { 342 this.con.commit(); 343 } else { 344 this.con.rollback(); 345 } 346 } catch (SQLException se) { 347 getLogger().warn("Could not commit or rollback connection", se); 348 } 349 350 try { 351 this.con.close(); 352 } catch (SQLException se) { 353 getLogger().warn("Could not close connection", se); 354 } 355 356 this.con = null; 357 } 358 359 if (this.datasource != null) { 360 this.dbselector.release(this.datasource); 361 this.datasource = null; 362 } 363 } 364 365 368 public void dispose() 369 { 370 this.manager.release(this.dbselector); 371 } 372 373 public String getMimeType() { 374 return (this.mimeType != null ? 375 this.mimeType : 376 this.parameters.getParameter("content-type", super.getMimeType())); 377 } 378 379 } 380 | Popular Tags |