001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.db.generic; 029 030import org.opencms.configuration.CmsConfigurationManager; 031import org.opencms.configuration.CmsParameterConfiguration; 032import org.opencms.configuration.CmsStoredContentInfoCacheConfiguration; 033import org.opencms.configuration.CmsSystemConfiguration; 034import org.opencms.configuration.CmsVfsConfiguration; 035import org.opencms.db.CmsDbContext; 036import org.opencms.db.CmsDbSqlException; 037import org.opencms.db.CmsDriverManager; 038import org.opencms.db.storage.CmsNoopStoredContentInfoCache; 039import org.opencms.db.storage.CmsStorageException; 040import org.opencms.db.storage.CmsStorageManager; 041import org.opencms.db.storage.CmsStorageManager.StorageResult; 042import org.opencms.db.storage.CmsStoredContentInfoCacheKey; 043import org.opencms.db.storage.I_CmsStorageDelivery; 044import org.opencms.db.storage.I_CmsStoredContentInfoCache; 045import org.opencms.db.storage.I_CmsStoredContentInfoCacheFactory; 046import org.opencms.db.storage.policy.CmsStoragePolicyContext; 047import org.opencms.file.CmsDataAccessException; 048import org.opencms.file.CmsFile; 049import org.opencms.file.CmsProject; 050import org.opencms.file.CmsResource; 051import org.opencms.file.CmsStoredContentInfo; 052import org.opencms.file.CmsVfsResourceNotFoundException; 053import org.opencms.file.I_CmsFileContentStreamHandler; 054import org.opencms.main.CmsInitException; 055import org.opencms.main.OpenCms; 056import org.opencms.util.CmsStringUtil; 057import org.opencms.util.CmsUUID; 058 059import java.io.ByteArrayInputStream; 060import java.io.OutputStream; 061import java.sql.Connection; 062import java.sql.PreparedStatement; 063import java.sql.ResultSet; 064import java.sql.SQLException; 065import java.util.ArrayList; 066import java.util.List; 067 068/** 069 * Integrates the OpenCms deduplicating media storage engine (DMSE) with VFS content operations.<p> 070 * 071 * This driver reads and writes storage identifiers and content hashes alongside 072 * VFS content rows. It delegates backend access to the storage manager and 073 * supports content in both the regular VFS content columns and storage backends.<p> 074 * 075 * @see org.opencms.db.storage.CmsStorageManager 076 */ 077public class CmsStorageVfsDriver extends CmsVfsDriver { 078 079 /** 080 * Performs one variant of reading content from a VFS content row.<p> 081 * 082 * @param <T> the handler result type 083 */ 084 private interface I_CmsContentReadOperation<T> { 085 086 /** 087 * Reads content described by a content row.<p> 088 * 089 * @param localContent the local file content bytes 090 * @param storage the external storage identifier 091 * @param hash the external storage hash 092 * @return the handler result 093 * @throws CmsStorageException if external storage content can not be loaded 094 */ 095 T read(byte[] localContent, String storage, String hash) throws CmsStorageException; 096 } 097 098 /** The filename/path of the storage SQL query properties. */ 099 private static final String STORAGE_QUERY_PROPERTIES = "org/opencms/db/generic/storage.properties"; 100 101 protected CmsStorageManager m_storageManager; 102 103 /** The stored content info cache. */ 104 protected I_CmsStoredContentInfoCache m_storedContentInfoCache = new CmsNoopStoredContentInfoCache(); 105 106 /** 107 * @see org.opencms.db.I_CmsVfsDriver#createContent(CmsDbContext, CmsUUID, CmsResource, byte[]) 108 */ 109 public void createContent(CmsDbContext dbc, CmsUUID projectId, CmsResource resource, byte[] content) 110 throws CmsDataAccessException { 111 112 Connection conn = null; 113 PreparedStatement stmt = null; 114 try { 115 StorageResult storageResult = m_storageManager.prepareContent( 116 dbc, 117 new CmsStoragePolicyContext(content, resource)); 118 byte[] fileContent = storageResult.getFileContent(); 119 String storage = storageResult.getStorage(); 120 String hash = storageResult.getHash(); 121 conn = m_sqlManager.getConnection(dbc); 122 // create new offline content 123 stmt = m_sqlManager.getPreparedStatement(conn, "C_OFFLINE_CONTENTS_WRITE"); 124 stmt.setString(1, resource.getResourceId().toString()); 125 if (fileContent.length < 2000) { 126 stmt.setBytes(2, fileContent); 127 } else { 128 stmt.setBinaryStream(2, new ByteArrayInputStream(fileContent), fileContent.length); 129 } 130 stmt.setString(3, storage); 131 stmt.setString(4, hash); 132 stmt.executeUpdate(); 133 m_storedContentInfoCache.clear(); 134 } catch (SQLException e) { 135 throw new CmsDbSqlException( 136 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 137 e); 138 } finally { 139 m_sqlManager.closeAll(dbc, conn, stmt, null); 140 } 141 } 142 143 /** 144 * @see org.opencms.db.I_CmsVfsDriver#createFile(CmsDbContext, java.sql.ResultSet, CmsUUID) 145 */ 146 public CmsFile createFile(CmsDbContext dbc, ResultSet res, CmsUUID projectId) 147 throws CmsDataAccessException, SQLException { 148 149 // use the super class to read all standard properties 150 CmsFile file = super.createFile(dbc, res, projectId); 151 // read the storage information 152 String storage = res.getString("STORAGE"); 153 // file content is stored locally -> return the file 154 if (CmsStringUtil.isEmpty(storage)) { 155 return file; 156 } 157 // load the file content from the storage 158 String hash = res.getString("HASH"); 159 byte[] finalContent; 160 try { 161 finalContent = m_storageManager.loadContent(dbc, file.getContents(), storage, hash); 162 } catch (CmsStorageException e) { 163 throw createStorageReadException(storage, hash, e); 164 } 165 // copy the file but use the file content from the storage 166 if (finalContent != file.getContents()) { 167 return new CmsFile( 168 file.getStructureId(), 169 file.getResourceId(), 170 file.getRootPath(), 171 file.getTypeId(), 172 file.getFlags(), 173 projectId, 174 file.getState(), 175 file.getDateCreated(), 176 file.getUserCreated(), 177 file.getDateLastModified(), 178 file.getUserLastModified(), 179 file.getDateReleased(), 180 file.getDateExpired(), 181 file.getSiblingCount(), 182 file.getLength(), 183 file.getDateContent(), 184 file.getVersion(), 185 finalContent); 186 } 187 return file; 188 } 189 190 /** 191 * @see org.opencms.db.I_CmsVfsDriver#createFile(CmsDbContext, java.sql.ResultSet, CmsUUID, boolean) 192 */ 193 public CmsFile createFile(CmsDbContext dbc, ResultSet res, CmsUUID projectId, boolean hasFileContentInResultSet) 194 throws CmsDataAccessException, SQLException { 195 196 CmsFile file = super.createFile(dbc, res, projectId, hasFileContentInResultSet); 197 if (!hasFileContentInResultSet) { // content is not relevant 198 return file; 199 } 200 String storage = res.getString("STORAGE"); 201 if (CmsStringUtil.isEmpty(storage)) { // content is stored locally, already read by standard VFS driver 202 return file; 203 } 204 // load the content from the storage 205 String hash = res.getString("HASH"); 206 byte[] finalContent; 207 try { 208 finalContent = m_storageManager.loadContent(dbc, file.getContents(), storage, hash); 209 } catch (CmsStorageException e) { 210 throw createStorageReadException(storage, hash, e); 211 } 212 if (finalContent != file.getContents()) { 213 return new CmsFile( 214 file.getStructureId(), 215 file.getResourceId(), 216 file.getRootPath(), 217 file.getTypeId(), 218 file.getFlags(), 219 file.getProjectLastModified(), 220 file.getState(), 221 file.getDateCreated(), 222 file.getUserCreated(), 223 file.getDateLastModified(), 224 file.getUserLastModified(), 225 file.getDateReleased(), 226 file.getDateExpired(), 227 file.getSiblingCount(), 228 file.getLength(), 229 file.getDateContent(), 230 file.getVersion(), 231 finalContent); 232 } 233 return file; 234 } 235 236 /** 237 * @see org.opencms.db.I_CmsVfsDriver#createOnlineContent(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, byte[], int, boolean, boolean) 238 */ 239 public void createOnlineContent( 240 CmsDbContext dbc, 241 CmsUUID resourceId, 242 byte[] contents, 243 int publishTag, 244 boolean keepOnline, 245 boolean needToUpdateContent) 246 throws CmsDataAccessException { 247 248 Connection conn = null; 249 PreparedStatement stmt = null; 250 ResultSet res = null; 251 String oldOnlineStorage = null; 252 String oldOnlineHash = null; 253 try { 254 conn = m_sqlManager.getConnection(dbc); 255 boolean dbcHasProjectId = (dbc.getProjectId() != null) && !dbc.getProjectId().isNullUUID(); 256 if (needToUpdateContent || dbcHasProjectId) { 257 // read the hash of the actual online content 258 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_FILES_CONTENT"); 259 stmt.setString(1, resourceId.toString()); 260 res = stmt.executeQuery(); 261 if (res.next()) { 262 oldOnlineStorage = res.getString("STORAGE"); 263 oldOnlineHash = res.getString("HASH"); 264 } 265 m_sqlManager.closeAll(dbc, null, stmt, res); 266 // read the actual offline content to take over the actual storage policy if needed 267 String storage = null; 268 String hash = null; 269 stmt = m_sqlManager.getPreparedStatement(conn, "C_OFFLINE_FILES_CONTENT"); 270 stmt.setString(1, resourceId.toString()); 271 res = stmt.executeQuery(); 272 if (res.next()) { 273 storage = res.getString("STORAGE"); 274 hash = res.getString("HASH"); 275 } 276 m_sqlManager.closeAll(dbc, null, stmt, res); 277 // move the content to the history or delete it as does the standard VFS driver 278 if (dbcHasProjectId || !OpenCms.getSystemInfo().isHistoryEnabled()) { 279 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_DELETE"); 280 stmt.setString(1, resourceId.toString()); 281 stmt.executeUpdate(); 282 m_sqlManager.closeAll(dbc, null, stmt, null); 283 } else { 284 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_HISTORY"); 285 stmt.setString(1, resourceId.toString()); 286 stmt.executeUpdate(); 287 m_sqlManager.closeAll(dbc, null, stmt, null); 288 } 289 // write the new online content taking over the offline storage policy 290 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_WRITE"); 291 stmt.setString(1, resourceId.toString()); 292 // handle the local binary blob (the external blob was already created in the offline table) 293 if ((contents != null) && (contents.length > 0)) { 294 if (CmsStringUtil.isEmpty(hash)) { 295 if (contents.length < 2000) { 296 stmt.setBytes(2, contents); 297 } else { 298 stmt.setBinaryStream(2, new ByteArrayInputStream(contents), contents.length); 299 } 300 } else { 301 stmt.setBytes(2, new byte[0]); 302 } 303 } else { 304 stmt.setBytes(2, new byte[0]); 305 } 306 stmt.setString(3, storage); 307 stmt.setString(4, hash); 308 stmt.setInt(5, publishTag); 309 stmt.setInt(6, publishTag); 310 stmt.setInt(7, keepOnline ? 1 : 0); 311 stmt.executeUpdate(); 312 m_storedContentInfoCache.clear(); 313 m_sqlManager.closeAll(dbc, null, stmt, null); 314 // delete the old storage entry if necessary 315 if (CmsStringUtil.isNotEmpty(oldOnlineHash)) { 316 m_storageManager.deleteContent(dbc, oldOnlineStorage, oldOnlineHash); 317 } 318 } else { 319 // standard update in case the content blob is not relevant 320 super.createOnlineContent(dbc, resourceId, contents, publishTag, keepOnline, needToUpdateContent); 321 } 322 } catch (SQLException e) { 323 throw new CmsDbSqlException( 324 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 325 e); 326 } finally { 327 m_sqlManager.closeAll(dbc, conn, stmt, res); 328 } 329 } 330 331 /** 332 * @see org.opencms.db.I_CmsVfsDriver#deleteHistoryContent(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, int) 333 */ 334 @Override 335 public void deleteHistoryContent(CmsDbContext dbc, CmsUUID resourceId, int publishTagToKeep) 336 throws CmsDataAccessException { 337 338 Connection conn = null; 339 PreparedStatement stmt = null; 340 ResultSet res = null; 341 List<String[]> storageReferences = new ArrayList<String[]>(); 342 try { 343 conn = m_sqlManager.getConnection(dbc); 344 stmt = m_sqlManager.getPreparedStatement(conn, "C_CONTENT_HISTORY_STORAGE_READ"); 345 stmt.setString(1, resourceId.toString()); 346 stmt.setInt(2, publishTagToKeep); 347 res = stmt.executeQuery(); 348 while (res.next()) { 349 String storage = res.getString("STORAGE"); 350 String hash = res.getString("HASH"); 351 if (CmsStringUtil.isNotEmpty(storage) && CmsStringUtil.isNotEmpty(hash)) { 352 storageReferences.add(new String[] {storage, hash}); 353 } 354 } 355 } catch (SQLException e) { 356 throw new CmsDbSqlException( 357 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 358 e); 359 } finally { 360 m_sqlManager.closeAll(dbc, conn, stmt, res); 361 } 362 363 super.deleteHistoryContent(dbc, resourceId, publishTagToKeep); 364 365 for (String[] storageReference : storageReferences) { 366 m_storageManager.deleteContent(dbc, storageReference[0], storageReference[1]); 367 } 368 } 369 370 /** 371 * @see org.opencms.db.I_CmsVfsDriver#destroy() 372 */ 373 public void destroy() throws Throwable { 374 375 Throwable failure = null; 376 try { 377 if (m_storageManager != null) { 378 m_storageManager.close(); 379 } 380 } catch (Throwable e) { 381 failure = e; 382 } finally { 383 m_storageManager = null; 384 try { 385 super.destroy(); 386 } catch (Throwable e) { 387 if (failure == null) { 388 failure = e; 389 } else { 390 failure.addSuppressed(e); 391 } 392 } 393 } 394 if (failure != null) { 395 throw failure; 396 } 397 } 398 399 /** 400 * @see org.opencms.db.I_CmsVfsDriver#getStoredContentDelivery(org.opencms.db.CmsDbContext, java.lang.String) 401 */ 402 @Override 403 public I_CmsStorageDelivery getStoredContentDelivery(CmsDbContext dbc, String storage) 404 throws CmsDataAccessException { 405 406 try { 407 return m_storageManager.getDeliveryStorage(storage); 408 } catch (CmsStorageException e) { 409 throw createStorageReadException(storage, null, e); 410 } 411 } 412 413 /** 414 * @see org.opencms.db.I_CmsDriver#init(org.opencms.db.CmsDbContext, org.opencms.configuration.CmsConfigurationManager, java.util.List, org.opencms.db.CmsDriverManager) 415 */ 416 public void init( 417 CmsDbContext dbc, 418 CmsConfigurationManager configurationManager, 419 List<String> successiveDrivers, 420 CmsDriverManager driverManager) { 421 422 super.init(dbc, configurationManager, successiveDrivers, driverManager); 423 try { 424 CmsParameterConfiguration configuration = configurationManager.getConfiguration(); 425 CmsVfsConfiguration vfsConfiguration = (CmsVfsConfiguration)configurationManager.getConfiguration( 426 CmsVfsConfiguration.class); 427 CmsSystemConfiguration systemConfiguration = (CmsSystemConfiguration)configurationManager.getConfiguration( 428 CmsSystemConfiguration.class); 429 m_storedContentInfoCache = createStoredContentInfoCache( 430 systemConfiguration.getStoredContentInfoCacheConfiguration()); 431 m_storageManager = new CmsStorageManager( 432 m_sqlManager, 433 configuration, 434 vfsConfiguration.getStoragePolicyConfiguration()); 435 m_storageManager.validateStorages(dbc); 436 } catch (Exception e) { 437 throw new CmsInitException(Messages.get().container(Messages.ERR_INITIALIZING_VFS_DRIVER_0), e); 438 } 439 } 440 441 /** 442 * @see org.opencms.db.I_CmsVfsDriver#initSqlManager(String) 443 */ 444 @Override 445 public org.opencms.db.generic.CmsSqlManager initSqlManager(String classname) { 446 447 return CmsSqlManager.getInstance(classname); 448 } 449 450 /** 451 * @see org.opencms.db.generic.CmsVfsDriver#initSqlManager(String, List) 452 */ 453 @Override 454 public org.opencms.db.generic.CmsSqlManager initSqlManager( 455 String classname, 456 List<String> additionalQueryProperties) { 457 458 return CmsSqlManager.getInstance(classname, additionalQueryProperties); 459 } 460 461 /** 462 * @see org.opencms.db.I_CmsVfsDriver#readContent(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.util.CmsUUID) 463 */ 464 public byte[] readContent(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId) throws CmsDataAccessException { 465 466 return readContentInternal(dbc, projectId, resourceId, new I_CmsContentReadOperation<byte[]>() { 467 468 public byte[] read(byte[] localContent, String storage, String hash) throws CmsStorageException { 469 470 return m_storageManager.loadContent(dbc, localContent, storage, hash); 471 } 472 }); 473 } 474 475 /** 476 * @see org.opencms.db.I_CmsVfsDriver#readContentFrom(CmsDbContext, CmsUUID, CmsUUID, I_CmsFileContentStreamHandler) 477 */ 478 @Override 479 public void readContentFrom( 480 CmsDbContext dbc, 481 CmsUUID projectId, 482 CmsUUID resourceId, 483 I_CmsFileContentStreamHandler handler) 484 throws CmsDataAccessException { 485 486 readContentInternal(dbc, projectId, resourceId, new I_CmsContentReadOperation<Void>() { 487 488 public Void read(byte[] localContent, String storage, String hash) throws CmsStorageException { 489 490 m_storageManager.loadContentFrom(dbc, localContent, storage, hash, handler); 491 return null; 492 } 493 }); 494 } 495 496 /** 497 * @see org.opencms.db.I_CmsVfsDriver#readContentTo(CmsDbContext, CmsUUID, CmsUUID, OutputStream) 498 */ 499 @Override 500 public void readContentTo(CmsDbContext dbc, CmsUUID projectId, CmsUUID resourceId, OutputStream out) 501 throws CmsDataAccessException { 502 503 readContentInternal(dbc, projectId, resourceId, new I_CmsContentReadOperation<Void>() { 504 505 public Void read(byte[] localContent, String storage, String hash) throws CmsStorageException { 506 507 m_storageManager.loadContentTo(dbc, localContent, storage, hash, out); 508 return null; 509 } 510 }); 511 } 512 513 /** 514 * @see org.opencms.db.I_CmsVfsDriver#readHistoryContent(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, int) 515 */ 516 public byte[] readHistoryContent(CmsDbContext dbc, CmsUUID resourceId, int publishTag) 517 throws CmsDataAccessException { 518 519 Connection conn = null; 520 PreparedStatement stmt = null; 521 ResultSet res = null; 522 byte[] content = null; 523 524 try { 525 conn = m_sqlManager.getConnection(dbc); 526 stmt = m_sqlManager.getPreparedStatement(conn, "C_HISTORY_READ_CONTENT"); 527 stmt.setString(1, resourceId.toString()); 528 stmt.setInt(2, publishTag); 529 stmt.setInt(3, publishTag); 530 res = stmt.executeQuery(); 531 532 if (res.next()) { 533 byte[] localContent = m_sqlManager.getBytes(res, m_sqlManager.readQuery("C_RESOURCES_FILE_CONTENT")); 534 String storage = res.getString("STORAGE"); 535 String hash = res.getString("HASH"); 536 try { 537 content = m_storageManager.loadContent(dbc, localContent, storage, hash); 538 } catch (CmsStorageException e) { 539 throw createStorageReadException(storage, hash, e); 540 } 541 while (res.next()) { 542 // do nothing only move through all rows because of mssql odbc driver 543 } 544 } 545 } catch (SQLException e) { 546 throw new CmsDbSqlException( 547 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 548 e); 549 } finally { 550 m_sqlManager.closeAll(dbc, conn, stmt, res); 551 } 552 return content; 553 } 554 555 /** 556 * @see org.opencms.db.I_CmsVfsDriver#readStoredContentInfo(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, org.opencms.file.CmsResource) 557 */ 558 @Override 559 public CmsStoredContentInfo readStoredContentInfo(CmsDbContext dbc, CmsUUID projectId, CmsResource resource) 560 throws CmsDataAccessException { 561 562 CmsStoredContentInfoCacheKey cacheKey = new CmsStoredContentInfoCacheKey(projectId, resource); 563 CmsStoredContentInfo cachedInfo = m_storedContentInfoCache.get(cacheKey); 564 if (cachedInfo != null) { 565 return cachedInfo; 566 } 567 Connection conn = null; 568 PreparedStatement stmt = null; 569 ResultSet res = null; 570 try { 571 conn = m_sqlManager.getConnection(dbc); 572 if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) { 573 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ONLINE_STORED_CONTENT_INFO"); 574 } else { 575 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_OFFLINE_STORED_CONTENT_INFO"); 576 } 577 stmt.setString(1, resource.getResourceId().toString()); 578 res = stmt.executeQuery(); 579 if (res.next()) { 580 String storage = res.getString("STORAGE"); 581 String hash = res.getString("HASH"); 582 while (res.next()) { 583 // do nothing only move through all rows because of mssql odbc driver 584 } 585 CmsStoredContentInfo info = new CmsStoredContentInfo(resource, storage, hash, resource.getLength()); 586 m_storedContentInfoCache.put(cacheKey, info); 587 return info; 588 } 589 throw new CmsVfsResourceNotFoundException( 590 Messages.get().container( 591 Messages.ERR_READ_CONTENT_WITH_RESOURCE_ID_2, 592 resource.getResourceId(), 593 Boolean.valueOf(projectId.equals(CmsProject.ONLINE_PROJECT_ID)))); 594 } catch (SQLException e) { 595 throw new CmsDbSqlException( 596 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 597 e); 598 } finally { 599 m_sqlManager.closeAll(dbc, conn, stmt, res); 600 } 601 } 602 603 /** 604 * @see org.opencms.db.I_CmsVfsDriver#removeFile(org.opencms.db.CmsDbContext, CmsUUID, org.opencms.file.CmsResource) 605 */ 606 public void removeFile(CmsDbContext dbc, CmsUUID projectId, CmsResource resource) throws CmsDataAccessException { 607 608 PreparedStatement stmt = null; 609 ResultSet res = null; 610 Connection conn = null; 611 CmsUUID resourceId = resource.getResourceId(); 612 try { 613 conn = m_sqlManager.getConnection(dbc); 614 if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) { 615 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ONLINE_FILES_CONTENT"); 616 } else { 617 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_OFFLINE_FILES_CONTENT"); 618 } 619 stmt.setString(1, resourceId.toString()); 620 res = stmt.executeQuery(); 621 if (res.next()) { 622 String storage = res.getString("STORAGE"); 623 String hash = res.getString("HASH"); 624 while (res.next()) { 625 // do nothing only move through all rows because of mssql odbc driver 626 } 627 m_sqlManager.closeAll(dbc, null, stmt, res); 628 super.removeFile(dbc, projectId, resource); 629 // remove the file if in storage 630 if (CmsStringUtil.isNotEmpty(storage)) { 631 m_storageManager.deleteContent(dbc, storage, hash); 632 } 633 634 } 635 super.removeFile(dbc, projectId, resource); 636 m_storedContentInfoCache.clear(); 637 } catch (SQLException e) { 638 throw new CmsDbSqlException( 639 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 640 e); 641 } finally { 642 m_sqlManager.closeAll(dbc, conn, stmt, res); 643 } 644 } 645 646 /** 647 * @see org.opencms.db.I_CmsVfsDriver#writeContent(org.opencms.db.CmsDbContext, org.opencms.file.CmsResource, byte[]) 648 */ 649 public void writeContent(CmsDbContext dbc, CmsResource resource, byte[] content) throws CmsDataAccessException { 650 651 Connection conn = null; 652 PreparedStatement stmt = null; 653 ResultSet res = null; 654 String oldStorage = null; 655 String oldHash = null; 656 try { 657 // read the actual offline content 658 conn = m_sqlManager.getConnection(dbc); 659 stmt = m_sqlManager.getPreparedStatement(conn, "C_OFFLINE_FILES_CONTENT"); 660 stmt.setString(1, resource.getResourceId().toString()); 661 res = stmt.executeQuery(); 662 if (res.next()) { 663 oldStorage = res.getString("STORAGE"); 664 oldHash = res.getString("HASH"); 665 } 666 m_sqlManager.closeAll(dbc, null, stmt, res); 667 // prepare to store the content blob 668 StorageResult storageResult = m_storageManager.prepareContent( 669 dbc, 670 new CmsStoragePolicyContext(content, resource)); 671 stmt = m_sqlManager.getPreparedStatement(conn, "C_OFFLINE_CONTENTS_UPDATE"); 672 // update the contents table 673 byte[] fileContent = storageResult.getFileContent(); 674 if (fileContent.length < 2000) { 675 stmt.setBytes(1, fileContent); 676 } else { 677 stmt.setBinaryStream(1, new ByteArrayInputStream(fileContent), fileContent.length); 678 } 679 stmt.setString(2, storageResult.getStorage()); 680 stmt.setString(3, storageResult.getHash()); 681 stmt.setString(4, resource.getResourceId().toString()); 682 stmt.executeUpdate(); 683 m_storedContentInfoCache.clear(); 684 // delete the old content blob if not used any more 685 if (CmsStringUtil.isNotEmpty(oldHash)) { 686 m_storageManager.deleteContent(dbc, oldStorage, oldHash); 687 } 688 } catch (SQLException e) { 689 throw new CmsDbSqlException( 690 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 691 e); 692 } finally { 693 m_sqlManager.closeAll(dbc, conn, stmt, res); 694 } 695 } 696 697 /** 698 * Creates the stored content info cache.<p> 699 * 700 * @param configuration the cache configuration 701 * @return the cache 702 * @throws Exception if the configured factory can not be created 703 */ 704 protected I_CmsStoredContentInfoCache createStoredContentInfoCache( 705 CmsStoredContentInfoCacheConfiguration configuration) 706 throws Exception { 707 708 if ((configuration == null) || !configuration.isEnabled()) { 709 return new CmsNoopStoredContentInfoCache(); 710 } 711 Class<?> factoryClass = Class.forName(configuration.getFactoryClass()); 712 if (!I_CmsStoredContentInfoCacheFactory.class.isAssignableFrom(factoryClass)) { 713 throw new CmsInitException(Messages.get().container(Messages.ERR_INITIALIZING_VFS_DRIVER_0)); 714 } 715 I_CmsStoredContentInfoCacheFactory factory = (I_CmsStoredContentInfoCacheFactory)factoryClass.getDeclaredConstructor().newInstance(); 716 I_CmsStoredContentInfoCache cache = factory.create(configuration); 717 return cache != null ? cache : new CmsNoopStoredContentInfoCache(); 718 } 719 720 /** 721 * @see org.opencms.db.generic.CmsVfsDriver#getAdditionalSqlQueryProperties(CmsParameterConfiguration) 722 */ 723 @Override 724 protected List<String> getAdditionalSqlQueryProperties(CmsParameterConfiguration configuration) { 725 726 List<String> result = new ArrayList<String>(); 727 result.add(STORAGE_QUERY_PROPERTIES); 728 return result; 729 } 730 731 /** 732 * Creates the data access exception for storage read failures.<p> 733 * 734 * @param storage the storage identifier 735 * @param hash the content hash 736 * @param cause the storage exception 737 * @return the data access exception 738 */ 739 private CmsDataAccessException createStorageReadException(String storage, String hash, CmsStorageException cause) { 740 741 return new CmsDataAccessException( 742 Messages.get().container(Messages.ERR_STORAGE_CONTENT_READ_2, storage, hash), 743 cause); 744 } 745 746 /** 747 * Reads a content row and delegates content loading to the given read operation.<p> 748 * 749 * @param dbc the database context 750 * @param projectId the project id 751 * @param resourceId the resource id 752 * @param readOperation the content read operation 753 * @return the read operation result 754 * @throws CmsDataAccessException if the content can not be read 755 */ 756 private <T> T readContentInternal( 757 CmsDbContext dbc, 758 CmsUUID projectId, 759 CmsUUID resourceId, 760 I_CmsContentReadOperation<T> readOperation) 761 throws CmsDataAccessException { 762 763 PreparedStatement stmt = null; 764 ResultSet res = null; 765 Connection conn = null; 766 T result = null; 767 try { 768 conn = m_sqlManager.getConnection(dbc); 769 if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) { 770 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ONLINE_FILES_CONTENT"); 771 } else { 772 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_OFFLINE_FILES_CONTENT"); 773 } 774 stmt.setString(1, resourceId.toString()); 775 res = stmt.executeQuery(); 776 if (res.next()) { 777 byte[] localContent = m_sqlManager.getBytes(res, m_sqlManager.readQuery("C_RESOURCES_FILE_CONTENT")); 778 String storage = res.getString("STORAGE"); 779 String hash = res.getString("HASH"); 780 try { 781 result = readOperation.read(localContent, storage, hash); 782 } catch (CmsStorageException e) { 783 throw createStorageReadException(storage, hash, e); 784 } 785 while (res.next()) { 786 // do nothing only move through all rows because of mssql odbc driver 787 } 788 } else { 789 throw new CmsVfsResourceNotFoundException( 790 Messages.get().container( 791 Messages.ERR_READ_CONTENT_WITH_RESOURCE_ID_2, 792 resourceId, 793 Boolean.valueOf(projectId.equals(CmsProject.ONLINE_PROJECT_ID)))); 794 } 795 } catch (SQLException e) { 796 throw new CmsDbSqlException( 797 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 798 e); 799 } finally { 800 m_sqlManager.closeAll(dbc, conn, stmt, res); 801 } 802 return result; 803 } 804}