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.oracle; 029 030import org.opencms.db.CmsDbContext; 031import org.opencms.db.CmsDbEntryNotFoundException; 032import org.opencms.db.CmsDbIoException; 033import org.opencms.db.CmsDbSqlException; 034import org.opencms.db.generic.CmsSqlManager; 035import org.opencms.db.generic.Messages; 036import org.opencms.db.storage.CmsStorageManager.StorageResult; 037import org.opencms.db.storage.policy.CmsStoragePolicyContext; 038import org.opencms.file.CmsDataAccessException; 039import org.opencms.file.CmsProject; 040import org.opencms.file.CmsResource; 041import org.opencms.main.OpenCms; 042import org.opencms.util.CmsStringUtil; 043import org.opencms.util.CmsUUID; 044 045import java.io.IOException; 046import java.io.OutputStream; 047import java.sql.Connection; 048import java.sql.PreparedStatement; 049import java.sql.ResultSet; 050import java.sql.SQLException; 051 052/** 053 * Oracle VFS driver for the OpenCms deduplicating media storage engine (DMSE).<p> 054 * 055 * @see org.opencms.db.generic.CmsStorageVfsDriver 056 * @see org.opencms.db.storage.CmsStorageManager 057 */ 058public class CmsStorageVfsDriver extends org.opencms.db.generic.CmsStorageVfsDriver { 059 060 /** 061 * @see org.opencms.db.I_CmsVfsDriver#createContent(CmsDbContext, CmsUUID, CmsResource, byte[]) 062 */ 063 @Override 064 public void createContent(CmsDbContext dbc, CmsUUID projectId, CmsResource resource, byte[] content) 065 throws CmsDataAccessException { 066 067 Connection conn = null; 068 PreparedStatement stmt = null; 069 StorageResult storageResult = m_storageManager.prepareContent( 070 dbc, 071 new CmsStoragePolicyContext(content, resource)); 072 try { 073 conn = m_sqlManager.getConnection(dbc); 074 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ORACLE_OFFLINE_CONTENTS_WRITE_STORAGE"); 075 stmt.setString(1, resource.getResourceId().toString()); 076 stmt.setString(2, storageResult.getStorage()); 077 stmt.setString(3, storageResult.getHash()); 078 stmt.executeUpdate(); 079 } catch (SQLException e) { 080 throw new CmsDbSqlException( 081 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 082 e); 083 } finally { 084 m_sqlManager.closeAll(dbc, conn, stmt, null); 085 } 086 087 internalWriteContent(dbc, projectId, resource.getResourceId(), storageResult.getFileContent(), -1); 088 } 089 090 /** 091 * @see org.opencms.db.I_CmsVfsDriver#createOnlineContent(CmsDbContext, CmsUUID, byte[], int, boolean, boolean) 092 */ 093 @Override 094 public void createOnlineContent( 095 CmsDbContext dbc, 096 CmsUUID resourceId, 097 byte[] contents, 098 int publishTag, 099 boolean keepOnline, 100 boolean needToUpdateContent) 101 throws CmsDataAccessException { 102 103 Connection conn = null; 104 PreparedStatement stmt = null; 105 ResultSet res = null; 106 String oldOnlineStorage = null; 107 String oldOnlineHash = null; 108 try { 109 conn = m_sqlManager.getConnection(dbc); 110 boolean dbcHasProjectId = (dbc.getProjectId() != null) && !dbc.getProjectId().isNullUUID(); 111 if (needToUpdateContent || dbcHasProjectId) { 112 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_FILES_CONTENT"); 113 stmt.setString(1, resourceId.toString()); 114 res = stmt.executeQuery(); 115 if (res.next()) { 116 oldOnlineStorage = res.getString("STORAGE"); 117 oldOnlineHash = res.getString("HASH"); 118 } 119 m_sqlManager.closeAll(dbc, null, stmt, res); 120 stmt = null; 121 res = null; 122 123 String storage = null; 124 String hash = null; 125 stmt = m_sqlManager.getPreparedStatement(conn, "C_OFFLINE_FILES_CONTENT"); 126 stmt.setString(1, resourceId.toString()); 127 res = stmt.executeQuery(); 128 if (res.next()) { 129 storage = res.getString("STORAGE"); 130 hash = res.getString("HASH"); 131 } 132 m_sqlManager.closeAll(dbc, null, stmt, res); 133 stmt = null; 134 res = null; 135 136 if (dbcHasProjectId || !OpenCms.getSystemInfo().isHistoryEnabled()) { 137 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_DELETE"); 138 stmt.setString(1, resourceId.toString()); 139 stmt.executeUpdate(); 140 m_sqlManager.closeAll(dbc, null, stmt, null); 141 stmt = null; 142 } else { 143 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_HISTORY"); 144 stmt.setString(1, resourceId.toString()); 145 stmt.executeUpdate(); 146 m_sqlManager.closeAll(dbc, null, stmt, null); 147 stmt = null; 148 } 149 150 stmt = m_sqlManager.getPreparedStatement(conn, "C_ORACLE_ONLINE_CONTENTS_WRITE_STORAGE"); 151 stmt.setString(1, resourceId.toString()); 152 stmt.setString(2, storage); 153 stmt.setString(3, hash); 154 stmt.setInt(4, publishTag); 155 stmt.setInt(5, publishTag); 156 stmt.setInt(6, keepOnline ? 1 : 0); 157 stmt.executeUpdate(); 158 m_sqlManager.closeAll(dbc, conn, stmt, null); 159 conn = null; 160 stmt = null; 161 162 if ((contents != null) && (contents.length > 0) && CmsStringUtil.isEmpty(hash)) { 163 internalWriteContent(dbc, CmsProject.ONLINE_PROJECT_ID, resourceId, contents, publishTag); 164 } 165 if (CmsStringUtil.isNotEmpty(oldOnlineHash)) { 166 m_storageManager.deleteContent(dbc, oldOnlineStorage, oldOnlineHash); 167 } 168 } else { 169 stmt = m_sqlManager.getPreparedStatement(conn, "C_HISTORY_CONTENTS_UPDATE"); 170 stmt.setInt(1, publishTag); 171 stmt.setString(2, resourceId.toString()); 172 stmt.executeUpdate(); 173 m_sqlManager.closeAll(dbc, null, stmt, null); 174 stmt = null; 175 176 if (!keepOnline) { 177 stmt = m_sqlManager.getPreparedStatement(conn, "C_ONLINE_CONTENTS_HISTORY"); 178 stmt.setString(1, resourceId.toString()); 179 stmt.executeUpdate(); 180 m_sqlManager.closeAll(dbc, null, stmt, null); 181 stmt = null; 182 } 183 } 184 } catch (SQLException e) { 185 throw new CmsDbSqlException( 186 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 187 e); 188 } finally { 189 m_sqlManager.closeAll(dbc, conn, stmt, res); 190 } 191 } 192 193 /** 194 * @see org.opencms.db.I_CmsVfsDriver#initSqlManager(String) 195 */ 196 @Override 197 public org.opencms.db.generic.CmsSqlManager initSqlManager(String classname) { 198 199 return CmsSqlManager.getInstance(classname); 200 } 201 202 /** 203 * @see org.opencms.db.generic.CmsVfsDriver#initSqlManager(String, java.util.List) 204 */ 205 @Override 206 public org.opencms.db.generic.CmsSqlManager initSqlManager( 207 String classname, 208 java.util.List<String> additionalQueryProperties) { 209 210 return CmsSqlManager.getInstance(classname, additionalQueryProperties); 211 } 212 213 /** 214 * @see org.opencms.db.I_CmsVfsDriver#writeContent(CmsDbContext, CmsResource, byte[]) 215 */ 216 @Override 217 public void writeContent(CmsDbContext dbc, CmsResource resource, byte[] content) throws CmsDataAccessException { 218 219 Connection conn = null; 220 PreparedStatement stmt = null; 221 ResultSet res = null; 222 String oldStorage = null; 223 String oldHash = null; 224 StorageResult storageResult = m_storageManager.prepareContent( 225 dbc, 226 new CmsStoragePolicyContext(content, resource)); 227 try { 228 conn = m_sqlManager.getConnection(dbc); 229 stmt = m_sqlManager.getPreparedStatement(conn, "C_OFFLINE_FILES_CONTENT"); 230 stmt.setString(1, resource.getResourceId().toString()); 231 res = stmt.executeQuery(); 232 if (res.next()) { 233 oldStorage = res.getString("STORAGE"); 234 oldHash = res.getString("HASH"); 235 } 236 m_sqlManager.closeAll(dbc, null, stmt, res); 237 stmt = null; 238 res = null; 239 240 stmt = m_sqlManager.getPreparedStatement(conn, "C_ORACLE_OFFLINE_CONTENTS_UPDATE_STORAGE"); 241 stmt.setString(1, storageResult.getStorage()); 242 stmt.setString(2, storageResult.getHash()); 243 stmt.setString(3, resource.getResourceId().toString()); 244 stmt.executeUpdate(); 245 m_sqlManager.closeAll(dbc, conn, stmt, null); 246 conn = null; 247 stmt = null; 248 } catch (SQLException e) { 249 throw new CmsDbSqlException( 250 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 251 e); 252 } finally { 253 m_sqlManager.closeAll(dbc, conn, stmt, res); 254 } 255 256 internalWriteContent( 257 dbc, 258 dbc.currentProject().getUuid(), 259 resource.getResourceId(), 260 storageResult.getFileContent(), 261 -1); 262 if (CmsStringUtil.isNotEmpty(oldHash)) { 263 m_storageManager.deleteContent(dbc, oldStorage, oldHash); 264 } 265 } 266 267 /** 268 * Writes the resource content with the specified resource id.<p> 269 * 270 * @param dbc the current database context 271 * @param projectId the id of the current project 272 * @param resourceId the id of the resource used to identify the content to update 273 * @param contents the new content of the file 274 * @param publishTag the publish tag if to be written to the online content 275 * 276 * @throws CmsDataAccessException if something goes wrong 277 */ 278 protected void internalWriteContent( 279 CmsDbContext dbc, 280 CmsUUID projectId, 281 CmsUUID resourceId, 282 byte[] contents, 283 int publishTag) 284 throws CmsDataAccessException { 285 286 PreparedStatement stmt = null; 287 PreparedStatement commit = null; 288 Connection conn = null; 289 ResultSet res = null; 290 291 boolean wasInTransaction = false; 292 try { 293 conn = m_sqlManager.getConnection(dbc); 294 if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) { 295 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ORACLE_ONLINE_CONTENTS_UPDATECONTENT"); 296 } else { 297 stmt = m_sqlManager.getPreparedStatement(conn, projectId, "C_ORACLE_OFFLINE_CONTENTS_UPDATECONTENT"); 298 } 299 300 wasInTransaction = !conn.getAutoCommit(); 301 if (!wasInTransaction) { 302 conn.setAutoCommit(false); 303 } 304 305 stmt.setString(1, resourceId.toString()); 306 if (projectId.equals(CmsProject.ONLINE_PROJECT_ID)) { 307 stmt.setInt(2, publishTag); 308 stmt.setInt(3, publishTag); 309 } 310 res = stmt.executeQuery(); 311 if (!res.next()) { 312 throw new CmsDbEntryNotFoundException( 313 Messages.get().container(Messages.LOG_READING_RESOURCE_1, resourceId)); 314 } 315 OutputStream output = CmsUserDriver.getOutputStreamFromBlob(res, "FILE_CONTENT"); 316 output.write(contents, 0, contents.length); 317 output.close(); 318 319 if (!wasInTransaction) { 320 commit = m_sqlManager.getPreparedStatement(conn, "C_COMMIT"); 321 commit.execute(); 322 m_sqlManager.closeAll(dbc, null, commit, null); 323 } 324 325 m_sqlManager.closeAll(dbc, null, stmt, res); 326 327 commit = null; 328 stmt = null; 329 res = null; 330 331 if (!wasInTransaction) { 332 conn.setAutoCommit(true); 333 } 334 } catch (IOException e) { 335 throw new CmsDbIoException( 336 Messages.get().container(Messages.ERR_WRITING_TO_OUTPUT_STREAM_1, resourceId), 337 e); 338 } catch (SQLException e) { 339 throw new CmsDbSqlException( 340 Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)), 341 e); 342 } finally { 343 org.opencms.db.oracle.CmsSqlManager.closeAllInTransaction( 344 m_sqlManager, 345 dbc, 346 conn, 347 stmt, 348 res, 349 commit, 350 wasInTransaction); 351 } 352 } 353}