001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://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 GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://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.CmsSelectQuery.TableAlias; 035import org.opencms.db.CmsSimpleQueryFragment; 036import org.opencms.db.I_CmsQueryFragment; 037import org.opencms.db.generic.CmsSqlManager; 038import org.opencms.db.generic.CmsUserQueryBuilder; 039import org.opencms.db.generic.Messages; 040import org.opencms.file.CmsDataAccessException; 041import org.opencms.util.CmsDataTypeUtil; 042import org.opencms.util.CmsUUID; 043 044import java.io.IOException; 045import java.io.OutputStream; 046import java.sql.Blob; 047import java.sql.Connection; 048import java.sql.PreparedStatement; 049import java.sql.ResultSet; 050import java.sql.SQLException; 051 052import com.google.common.base.Joiner; 053 054/** 055 * Oracle implementation of the user driver methods.<p> 056 * 057 * @since 6.0.0 058 */ 059public class CmsUserDriver extends org.opencms.db.generic.CmsUserDriver { 060 061 /** 062 * Generates an Output stream that writes to a blob, also truncating the existing blob if required.<p> 063 * 064 * Apparently Oracle requires some non-standard handling here.<p> 065 * 066 * @param res the result set where the blob is located in 067 * @param name the name of the database column where the blob is located 068 * @return an Output stream from a blob 069 * @throws SQLException if something goes wring 070 */ 071 public static OutputStream getOutputStreamFromBlob(ResultSet res, String name) throws SQLException { 072 073 Blob blob = res.getBlob(name); 074 blob.truncate(0); 075 return blob.setBinaryStream(0L); 076 } 077 078 /** 079 * @see org.opencms.db.generic.CmsUserDriver#createUserQueryBuilder() 080 */ 081 @Override 082 public CmsUserQueryBuilder createUserQueryBuilder() { 083 084 return new CmsUserQueryBuilder() { 085 086 /** 087 * @see org.opencms.db.generic.CmsUserQueryBuilder#createFlagCondition(org.opencms.db.CmsSelectQuery.TableAlias, int) 088 */ 089 @Override 090 protected I_CmsQueryFragment createFlagCondition(TableAlias users, int flags) { 091 092 return new CmsSimpleQueryFragment( 093 "BITAND(" + users.column("USER_FLAGS") + ", ?) = ? ", 094 Integer.valueOf(flags), 095 Integer.valueOf(flags)); 096 } 097 098 /** 099 * @see org.opencms.db.generic.CmsUserQueryBuilder#generateConcat(java.lang.String[]) 100 */ 101 @Override 102 protected String generateConcat(String... expressions) { 103 104 return Joiner.on(" || ").join(expressions); 105 } 106 107 /** 108 * @see org.opencms.db.generic.CmsUserQueryBuilder#getUserFlagExpression(org.opencms.db.CmsSelectQuery.TableAlias, int) 109 */ 110 @Override 111 protected String getUserFlagExpression(TableAlias users, int flags) { 112 113 return "BITAND(" + users.column("USER_FLAGS") + ", " + flags + ")"; 114 115 } 116 117 /** 118 * @see org.opencms.db.generic.CmsUserQueryBuilder#useWindowFunctionsForPaging() 119 */ 120 @Override 121 protected boolean useWindowFunctionsForPaging() { 122 123 return true; 124 } 125 126 }; 127 } 128 129 /** 130 * @see org.opencms.db.I_CmsUserDriver#initSqlManager(String) 131 */ 132 @Override 133 public org.opencms.db.generic.CmsSqlManager initSqlManager(String classname) { 134 135 return CmsSqlManager.getInstance(classname); 136 } 137 138 /** 139 * Updates additional user info.<p> 140 * @param dbc the current dbc 141 * @param userId the user id to add the user info for 142 * @param key the name of the additional user info 143 * @param value the value of the additional user info 144 * @throws CmsDataAccessException if something goes wrong 145 */ 146 @Override 147 protected void internalUpdateUserInfo(CmsDbContext dbc, CmsUUID userId, String key, Object value) 148 throws CmsDataAccessException { 149 150 PreparedStatement stmt = null; 151 Connection conn = null; 152 153 try { 154 155 // get connection 156 conn = m_sqlManager.getConnection(dbc); 157 158 // write data to database 159 stmt = m_sqlManager.getPreparedStatement(conn, "C_ORACLE_USERDATA_UPDATE_3"); 160 stmt.setString(1, value.getClass().getName()); 161 stmt.setString(2, userId.toString()); 162 stmt.setString(3, key); 163 stmt.executeUpdate(); 164 } catch (SQLException e) { 165 throw new CmsDbSqlException( 166 org.opencms.db.generic.Messages.get().container( 167 org.opencms.db.generic.Messages.ERR_GENERIC_SQL_1, 168 CmsDbSqlException.getErrorQuery(stmt)), 169 e); 170 } finally { 171 m_sqlManager.closeAll(dbc, conn, stmt, null); 172 } 173 internalUpdateUserInfoData(dbc, userId, key, value); 174 } 175 176 /** 177 * Updates the given user information entry.<p> 178 * 179 * @param dbc the current database context 180 * @param userId the id of the user to update 181 * @param key the user info entry key 182 * @param value the user info entry value 183 * 184 * @throws CmsDataAccessException if something goes wrong 185 */ 186 protected void internalUpdateUserInfoData(CmsDbContext dbc, CmsUUID userId, String key, Object value) 187 throws CmsDataAccessException { 188 189 PreparedStatement stmt = null; 190 PreparedStatement commit = null; 191 ResultSet res = null; 192 Connection conn = null; 193 194 boolean wasInTransaction = false; 195 196 try { 197 // get connection 198 conn = m_sqlManager.getConnection(dbc); 199 wasInTransaction = !conn.getAutoCommit(); 200 if (!wasInTransaction) { 201 conn.setAutoCommit(false); 202 } 203 204 // update user_info in this special way because of using blob 205 stmt = m_sqlManager.getPreparedStatement(conn, "C_ORACLE_USERDATA_UPDATE_2"); 206 stmt.setString(1, userId.toString()); 207 stmt.setString(2, key); 208 res = stmt.executeQuery(); 209 if (!res.next()) { 210 throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_NO_USER_WITH_ID_1, userId)); 211 } 212 // write serialized user info 213 OutputStream output = getOutputStreamFromBlob(res, "DATA_VALUE"); 214 output.write(CmsDataTypeUtil.dataSerialize(value)); 215 output.close(); 216 value = null; 217 218 if (!wasInTransaction) { 219 commit = m_sqlManager.getPreparedStatement(conn, "C_COMMIT"); 220 commit.execute(); 221 m_sqlManager.closeAll(dbc, null, commit, null); 222 } 223 m_sqlManager.closeAll(dbc, null, stmt, res); 224 225 // this is needed so the finally block works correctly 226 commit = null; 227 stmt = null; 228 res = null; 229 230 if (!wasInTransaction) { 231 conn.setAutoCommit(true); 232 } 233 } catch (SQLException e) { 234 throw new CmsDbSqlException( 235 org.opencms.db.generic.Messages.get().container( 236 org.opencms.db.generic.Messages.ERR_GENERIC_SQL_1, 237 CmsDbSqlException.getErrorQuery(stmt)), 238 e); 239 } catch (IOException e) { 240 throw new CmsDbIoException(Messages.get().container(Messages.ERR_SERIALIZING_USER_DATA_1, userId), e); 241 } finally { 242 org.opencms.db.oracle.CmsSqlManager.closeAllInTransaction( 243 m_sqlManager, 244 dbc, 245 conn, 246 stmt, 247 res, 248 commit, 249 wasInTransaction); 250 } 251 } 252 253 /** 254 * Writes a new additional user info.<p> 255 * @param dbc the current dbc 256 * @param userId the user id to add the user info for 257 * @param key the name of the additional user info 258 * @param value the value of the additional user info 259 * @throws CmsDataAccessException if something goes wrong 260 */ 261 @Override 262 protected void internalWriteUserInfo(CmsDbContext dbc, CmsUUID userId, String key, Object value) 263 throws CmsDataAccessException { 264 265 PreparedStatement stmt = null; 266 Connection conn = null; 267 268 try { 269 270 // get connection 271 conn = m_sqlManager.getConnection(dbc); 272 273 // write data to database 274 stmt = m_sqlManager.getPreparedStatement(conn, "C_ORACLE_USERDATA_WRITE_3"); 275 stmt.setString(1, userId.toString()); 276 stmt.setString(2, key); 277 stmt.setString(3, value.getClass().getName()); 278 stmt.executeUpdate(); 279 } catch (SQLException e) { 280 throw new CmsDbSqlException( 281 org.opencms.db.generic.Messages.get().container( 282 org.opencms.db.generic.Messages.ERR_GENERIC_SQL_1, 283 CmsDbSqlException.getErrorQuery(stmt)), 284 e); 285 } finally { 286 m_sqlManager.closeAll(dbc, conn, stmt, null); 287 } 288 internalUpdateUserInfoData(dbc, userId, key, value); 289 } 290 291}