001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.odfweb.cart; 017 018import java.sql.Connection; 019import java.sql.PreparedStatement; 020import java.sql.ResultSet; 021import java.sql.SQLException; 022import java.util.ArrayList; 023import java.util.Date; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027 028import org.apache.avalon.framework.component.Component; 029import org.apache.avalon.framework.configuration.Configurable; 030import org.apache.avalon.framework.configuration.Configuration; 031import org.apache.avalon.framework.configuration.ConfigurationException; 032import org.apache.commons.lang.StringUtils; 033 034import org.ametys.core.datasource.ConnectionHelper; 035import org.ametys.core.user.UserIdentity; 036import org.ametys.core.userpref.UserPreferencesException; 037import org.ametys.core.userpref.UserPreferencesStorage; 038import org.ametys.runtime.config.Config; 039import org.ametys.runtime.plugin.component.AbstractLogEnabled; 040 041 042/** 043 * Specific storage for odf cart user preferences 044 */ 045public class ODFCartUserPreferencesStorage extends AbstractLogEnabled implements UserPreferencesStorage, Configurable, Component 046{ 047 /** The Avalon Role */ 048 public static final String ROLE = ODFCartUserPreferencesStorage.class.getName(); 049 050 /** The id of the data source used. */ 051 protected String _dataSourceId; 052 053 /** The login column, cannot be null. */ 054 protected String _loginColumn; 055 056 /** The population id column, cannot be null. */ 057 protected String _populationColumn; 058 059 /** The context column, can be null if the database is not context-dependent. */ 060 protected String _contextColumn; 061 062 /** The content id column */ 063 protected String _contentIdColumn; 064 065 /** Mapping from preference id to table name. */ 066 protected Map<String, String> _prefIdToTable; 067 068 @Override 069 public void configure(Configuration configuration) throws ConfigurationException 070 { 071 // Data source id 072 Configuration dataSourceConf = configuration.getChild("datasource", false); 073 if (dataSourceConf == null) 074 { 075 throw new ConfigurationException("The 'datasource' configuration node must be defined.", dataSourceConf); 076 } 077 078 String dataSourceConfParam = dataSourceConf.getValue(); 079 String dataSourceConfType = dataSourceConf.getAttribute("type", "config"); 080 081 if (StringUtils.equals(dataSourceConfType, "config")) 082 { 083 _dataSourceId = Config.getInstance().getValue(dataSourceConfParam); 084 } 085 else // expecting type="id" 086 { 087 _dataSourceId = dataSourceConfParam; 088 } 089 090 // Default to "contentId". 091 _contentIdColumn = configuration.getChild("content-id").getValue("contentId"); 092 // Default to "login". 093 _loginColumn = configuration.getChild("loginColumn").getValue("login").toLowerCase(); 094 // Default to "population" 095 _populationColumn = configuration.getChild("populationColumn").getValue("population").toLowerCase(); 096 // Default to 'context' (no context column). 097 _contextColumn = configuration.getChild("contextColumn").getValue("context"); 098 099 // Configure the preference-table mappings. 100 configureMappings(configuration.getChild("mappings")); 101 } 102 103 /** 104 * Configure the mappings from preference ID to table name. 105 * @param configuration the mapping configuration root. 106 * @throws ConfigurationException if an error occurs. 107 */ 108 public void configureMappings(Configuration configuration) throws ConfigurationException 109 { 110 _prefIdToTable = new HashMap<>(); 111 112 for (Configuration mappingConf : configuration.getChildren("mapping")) 113 { 114 String prefId = mappingConf.getAttribute("prefId"); 115 String table = mappingConf.getAttribute("table"); 116 117 _prefIdToTable.put(prefId, table); 118 } 119 } 120 121 @Override 122 public Map<String, String> getUnTypedUserPrefs(UserIdentity user, String storageContext, Map<String, String> contextVars) throws UserPreferencesException 123 { 124 Map<String, String> prefs = new HashMap<>(); 125 126 for (String id : _prefIdToTable.keySet()) 127 { 128 prefs.put(id, getUserPreferenceAsString(user, storageContext, contextVars, id)); 129 } 130 131 return prefs; 132 } 133 134 @Override 135 public void removeUserPreferences(UserIdentity user, String storageContext, Map<String, String> contextVars) throws UserPreferencesException 136 { 137 Connection connection = null; 138 try 139 { 140 connection = ConnectionHelper.getConnection(_dataSourceId); 141 for (String id : _prefIdToTable.keySet()) 142 { 143 _removeUserPreferencesFromTable(connection, user, storageContext, _prefIdToTable.get(id)); 144 } 145 } 146 catch (SQLException e) 147 { 148 String message = "Database error trying to remove ODF cart preferences for user '" + user + "' in context '" + storageContext + "'."; 149 getLogger().error(message, e); 150 throw new UserPreferencesException(message, e); 151 } 152 finally 153 { 154 ConnectionHelper.cleanup(connection); 155 } 156 } 157 158 private void _removeUserPreferencesFromTable(Connection connection, UserIdentity user, String storageContext, String table) throws SQLException 159 { 160 PreparedStatement stmt = null; 161 162 try 163 { 164 StringBuilder query = new StringBuilder(); 165 query.append("DELETE FROM ").append(table).append(" WHERE ").append(_loginColumn).append(" = ? AND ").append(_populationColumn).append(" = ?"); 166 query.append(" AND ").append(_contextColumn).append(" = ?"); 167 168 stmt = connection.prepareStatement(query.toString()); 169 stmt.setString(1, user.getLogin()); 170 stmt.setString(2, user.getPopulationId()); 171 stmt.setString(3, storageContext); 172 173 stmt.executeUpdate(); 174 } 175 finally 176 { 177 ConnectionHelper.cleanup(stmt); 178 } 179 180 } 181 182 /** 183 * Remove content from all user preferences 184 * @param contentId the content id to remove 185 * @throws UserPreferencesException if failed to remove user preferences 186 */ 187 public void removeContentFromUserPreferences(String contentId) throws UserPreferencesException 188 { 189 Connection connection = null; 190 PreparedStatement stmt = null; 191 192 try 193 { 194 connection = ConnectionHelper.getConnection(_dataSourceId); 195 196 StringBuilder query = new StringBuilder(); 197 query.append("DELETE FROM ").append(_prefIdToTable.get(ODFCartManager.CART_USER_PREF_CONTENT_IDS)).append(" WHERE ").append(_contentIdColumn).append(" like ?"); 198 199 stmt = connection.prepareStatement(query.toString()); 200 201 stmt.setString(1, contentId + "%"); 202 stmt.executeUpdate(); 203 } 204 catch (SQLException e) 205 { 206 String message = "Database error trying to remove ODF content of id '" + contentId + "' from all user's preferences"; 207 getLogger().error(message, e); 208 throw new UserPreferencesException(message, e); 209 } 210 finally 211 { 212 ConnectionHelper.cleanup(stmt); 213 ConnectionHelper.cleanup(connection); 214 } 215 } 216 217 @Override 218 public void setUserPreferences(UserIdentity user, String storageContext, Map<String, String> contextVars, Map<String, String> preferences) throws UserPreferencesException 219 { 220 removeUserPreferences(user, storageContext, contextVars); 221 222 Connection connection = null; 223 try 224 { 225 connection = ConnectionHelper.getConnection(_dataSourceId); 226 _insertPreferences(connection, preferences, user, storageContext); 227 } 228 catch (SQLException e) 229 { 230 String message = "Database error trying to set ODF cart preferences of user '" + user + "' in context '" + storageContext + "'."; 231 getLogger().error(message, e); 232 throw new UserPreferencesException(message, e); 233 } 234 finally 235 { 236 ConnectionHelper.cleanup(connection); 237 } 238 } 239 240 private void _insertPreferences(Connection connection, Map<String, String> preferences, UserIdentity user, String storageContext) throws SQLException 241 { 242 for (String id : preferences.keySet()) 243 { 244 String table = _prefIdToTable.get(id); 245 246 String[] contentIdsTab = StringUtils.split(preferences.get(id), ","); 247 248 if (contentIdsTab.length > 0) 249 { 250 PreparedStatement stmt = null; 251 try 252 { 253 StringBuilder query = new StringBuilder(); 254 query.append("INSERT INTO ").append(table).append("(").append(_loginColumn).append(", ").append(_populationColumn); 255 query.append(", ").append(_contextColumn); 256 query.append(", ").append(_contentIdColumn); 257 258 StringBuilder values = new StringBuilder(); 259 for (int i = 0; i < contentIdsTab.length; i++) 260 { 261 if (i != 0) 262 { 263 values.append(","); 264 } 265 values.append("(?, ?, ?, ?)"); 266 } 267 268 query.append(") VALUES ").append(values); 269 270 int i = 1; 271 stmt = connection.prepareStatement(query.toString()); 272 273 for (String idContent : contentIdsTab) 274 { 275 stmt.setString(i++, user.getLogin()); 276 stmt.setString(i++, user.getPopulationId()); 277 stmt.setString(i++, storageContext); 278 stmt.setString(i++, idContent); 279 } 280 281 stmt.executeUpdate(); 282 } 283 finally 284 { 285 ConnectionHelper.cleanup(stmt); 286 } 287 } 288 } 289 290 } 291 292 @Override 293 public String getUserPreferenceAsString(UserIdentity user, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException 294 { 295 Connection connection = null; 296 PreparedStatement statement = null; 297 ResultSet rs = null; 298 String value = null; 299 String table = _prefIdToTable.get(id); 300 301 try 302 { 303 StringBuilder query = new StringBuilder(); 304 query.append("SELECT ").append(_contentIdColumn).append(" FROM ").append(table).append(" WHERE ").append(_loginColumn).append(" = ? AND ").append(_populationColumn).append(" = ?"); 305 query.append(" AND ").append(_contextColumn).append(" = ?"); 306 307 connection = ConnectionHelper.getConnection(_dataSourceId); 308 309 statement = connection.prepareStatement(query.toString()); 310 statement.setString(1, user.getLogin()); 311 statement.setString(2, user.getPopulationId()); 312 statement.setString(3, storageContext); 313 314 rs = statement.executeQuery(); 315 316 List<String> results = new ArrayList<>(); 317 while (rs.next()) 318 { 319 results.add(rs.getString(1)); 320 } 321 322 value = StringUtils.join(results, ","); 323 } 324 catch (SQLException e) 325 { 326 String message = "Database error trying to get ODF cart preferences of user '" + user + "' in context '" + storageContext + "'."; 327 getLogger().error(message, e); 328 throw new UserPreferencesException(message, e); 329 } 330 finally 331 { 332 ConnectionHelper.cleanup(rs); 333 ConnectionHelper.cleanup(statement); 334 ConnectionHelper.cleanup(connection); 335 } 336 337 return value; 338 } 339 340 @Override 341 public Long getUserPreferenceAsLong(UserIdentity user, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException 342 { 343 return null; 344 } 345 346 @Override 347 public Date getUserPreferenceAsDate(UserIdentity user, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException 348 { 349 return null; 350 } 351 352 @Override 353 public Boolean getUserPreferenceAsBoolean(UserIdentity user, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException 354 { 355 return null; 356 } 357 358 @Override 359 public Double getUserPreferenceAsDouble(UserIdentity user, String storageContext, Map<String, String> contextVars, String id) throws UserPreferencesException 360 { 361 return null; 362 } 363 364}