package org.sakaiproject.delegatedaccess.dao.impl;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.InvariantReloadingStrategy;
import org.apache.log4j.Logger;
import org.sakaiproject.component.cover.ServerConfigurationService;
import org.sakaiproject.delegatedaccess.dao.DelegatedAccessDao;
import org.sakaiproject.delegatedaccess.util.DelegatedAccessConstants;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class DelegatedAccessDaoImpl extends JdbcDaoSupport implements DelegatedAccessDao {
private static final Logger log = Logger.getLogger(DelegatedAccessDaoImpl.class);
private PropertiesConfiguration statements;
private static int ORACLE_IN_CLAUSE_SIZE_LIMIT = 1000;
private boolean oracle = false;
/**
* init
*/
public void init() {
log.info("init()");
//setup the vendor
String vendor = ServerConfigurationService.getInstance().getString("vendor@org.sakaiproject.db.api.SqlService", null);
//initialise the statements
initStatements(vendor);
if(vendor != null && "oracle".equals(vendor)){
oracle = true;
}
}
/**
* Loads our SQL statements from the appropriate properties file
* @param vendor DB vendor string. Must be one of mysql, oracle, hsqldb
*/
private void initStatements(String vendor) {
URL url = getClass().getClassLoader().getResource(vendor + ".properties");
try {
statements = new PropertiesConfiguration(); //must use blank constructor so it doesn't parse just yet (as it will split)
statements.setReloadingStrategy(new InvariantReloadingStrategy()); //don't watch for reloads
statements.setThrowExceptionOnMissing(true); //throw exception if no prop
statements.setDelimiterParsingDisabled(true); //don't split properties
statements.load(url); //now load our file
} catch (ConfigurationException e) {
log.error(e.getClass() + ": " + e.getMessage(), e);
return;
}
}
/**
* Get an SQL statement for the appropriate vendor from the bundle
* @param key
* @return statement or null if none found.
*/
private String getStatement(String key) {
try {
return statements.getString(key);
} catch (NoSuchElementException e) {
log.error("Statement: '" + key + "' could not be found in: " + statements.getFileName(), e);
return null;
}
}
@SuppressWarnings("unchecked")
public List<String> getDistinctSiteTerms(String termField) {
try{
return getJdbcTemplate().query(getStatement("select.distinctTerms"), new String[]{termField}, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString(1);
}
});
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
public String getSiteProperty(String propertyName, String siteId){
try{
return (String) getJdbcTemplate().queryForObject(getStatement("select.siteProperty"), new Object[]{propertyName, siteId}, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("VALUE");
}
});
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
public Map<String, List<String>> getNodesBySiteRef(String[] siteRefs, String hierarchyId){
try{
Map<String, List<String>> returnMap = new HashMap<String, List<String>>();
if(siteRefs == null || siteRefs.length == 0){
return returnMap;
}
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > siteRefs.length){
subArraySize = (siteRefs.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(siteRefs, subArrayIndex, subArrayIndex + subArraySize);
String query = getStatement("select.hierarchyNode");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'"; //escape apostrophe
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query = query.replace("(?)", inParams);
List<String[]> results = (List<String[]>) getJdbcTemplate().query(query, new Object[]{hierarchyId}, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return new String[]{resultSet.getString("title"), resultSet.getString("ID")};
}
});
if(results != null){
for(String[] result : results){
if(result != null && result.length == 2){
if(!returnMap.containsKey(result[0])){
returnMap.put(result[0], new ArrayList<String>());
}
returnMap.get(result[0]).add(result[1]);
}
}
}
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < siteRefs.length);
return returnMap;
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
public List<String> getEmptyNonSiteNodes(String hierarchyId){
try{
return (List<String>) getJdbcTemplate().query(getStatement("select.emptyNodes"), new Object[]{hierarchyId}, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("ID");
}
});
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
// public void addSiteProperty(String siteId, String propertyName, String propertyValue){
// try {
// getJdbcTemplate().update(getStatement("insert.siteProperty"),
// new Object[]{siteId, propertyName, propertyValue}
// );
// } catch (DataAccessException ex) {
// log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage());
// }
// }
public void updateSiteProperty(String[] siteIds, String propertyName, String propertyValue){
try {
if(siteIds == null || siteIds.length == 0){
return;
}
String query = getStatement("update.siteProperty");
if(oracle){
//Create Replace query:
String values = "";
for(String siteId : siteIds){
if(!"".equals(values)){
values += " union ";
}
values += "select '" + siteId + "' SITE_ID, '" + propertyName + "' NAME, '" + propertyValue + "' VALUE from dual";
}
query = query.replace("?", values);
}else{
//Create Replace query:
String values = "";
for(String siteId : siteIds){
if(!"".equals(values)){
values += ",";
}
values += "('" + siteId + "', '" + propertyName + "','" + propertyValue + "')";
}
query = query + values;
}
getJdbcTemplate().update(query);
} catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
}
}
public void removeSiteProperty(String[] siteIds, String propertyName){
try{
if(siteIds == null || siteIds.length == 0){
return;
}
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > siteIds.length){
subArraySize = (siteIds.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(siteIds, subArrayIndex, subArrayIndex + subArraySize);
String query1 = getStatement("delete.siteProperty");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query1 = query1.replace("(?)", inParams);
getJdbcTemplate().update(query1, new Object[]{propertyName});
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < siteIds.length);
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
}
}
public List<String[]> searchSites(String titleSearch, Map<String, String> propsMap, String[] instructorIds, String insturctorType, boolean publishedOnly){
try{
if(titleSearch == null){
titleSearch = "";
}
titleSearch ="%" + titleSearch + "%";
Object[] params = new Object[]{titleSearch};
String query = "";
final boolean noInstructors = instructorIds == null || instructorIds.length == 0;
//either grab the simple site search based on title or the one that limits by instructor ids
if(noInstructors){
query = getStatement("select.siteSearch");
}else{
if(DelegatedAccessConstants.ADVANCED_SEARCH_INSTRUCTOR_TYPE_MEMBER.equals(insturctorType)){
query = getStatement("select.siteSearchMembers");
}else{
//default is instructor search
query = getStatement("select.siteSearchInstructors");
}
String inParams = "(";
//to be on the safe side, I added oracle limit restriction, but hopefully no one is searching for
//more than 1000 instructors
for(int i = 0; i < instructorIds.length && i < ORACLE_IN_CLAUSE_SIZE_LIMIT; i++){
inParams += "'" + instructorIds[i].replace("'", "''") + "'";
if(i < instructorIds.length - 1){
inParams += ",";
}
}
inParams += ")";
query = query.replace("(:userIds)", inParams);
}
//add the site properties restrictions in the where clause
if(propsMap != null && propsMap.size() > 0){
params = new Object[1 + (propsMap.size() * 2)];
params[0] = titleSearch;
int i = 1;
for(Entry<String, String> entry : propsMap.entrySet()){
query += " " + getStatement("select.siteSearchPropWhere");
params[i] = entry.getKey();
i++;
params[i] = entry.getValue();
i++;
}
}
if(publishedOnly){
query += " " + getStatement("select.siteSearchPublishedOnly");
}
return (List<String[]>) getJdbcTemplate().query(query, params, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
if(noInstructors){
return new String[]{resultSet.getString("SITE_ID"), resultSet.getString("TITLE")};
}else{
return new String[]{resultSet.getString("SITE_ID"), resultSet.getString("TITLE"), resultSet.getString("USER_ID")};
}
}
});
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return new ArrayList<String[]>();
}
}
public Map<String, Map<String, String>> searchSitesForProp(String[] props, String[] siteIds){
try{
Map<String, Map<String, String>> returnMap = new HashMap<String, Map<String, String>>();
if(props == null || props.length == 0 || siteIds == null || siteIds.length == 0){
return returnMap;
}
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > siteIds.length){
subArraySize = (siteIds.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(siteIds, subArrayIndex, subArrayIndex + subArraySize);
String query = getStatement("select.sitesProp");
String propInParams = "(";
for(int i = 0; i < props.length; i++){
propInParams += "'" + props[i].replace("'", "''") + "'";
if(i < props.length - 1){
propInParams += ",";
}
}
propInParams += ")";
query = query.replace("(:props)", propInParams);
propInParams += ")";
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query = query.replace("(:siteIds)", inParams);
List<String[]> results = (List<String[]>) getJdbcTemplate().query(query, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return new String[]{resultSet.getString("SITE_ID"), resultSet.getString("NAME"), resultSet.getString("VALUE")};
}
});
if(results != null){
for(String[] result : results){
Map<String, String> propMap = new HashMap<String, String>();
if(returnMap.containsKey(result[0])){
propMap = returnMap.get(result[0]);
}
propMap.put(result[1], result[2]);
returnMap.put(result[0], propMap);
}
}
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < siteIds.length);
return returnMap;
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
public void cleanupOrphanedPermissions(){
try {
getJdbcTemplate().update(getStatement("delete.orphaned.permissions"));
} catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
}
}
public Map<String, Set<String>> getNodesAndPermsForUser(String userId, String[] nodeIds){
try{
Map<String, Set<String>> returnMap = new HashMap<String, Set<String>>();
if(nodeIds == null || nodeIds.length == 0){
return returnMap;
}
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > nodeIds.length){
subArraySize = (nodeIds.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(nodeIds, subArrayIndex, subArrayIndex + subArraySize);
String query = getStatement("select.nodes.and.perms.for.user");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query = query.replace("(?)", inParams);
List<String[]> results = (List<String[]>) getJdbcTemplate().query(query, new Object[]{userId}, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return new String[]{resultSet.getString("NODEID"), resultSet.getString("PERMISSION")};
}
});
if(results != null){
for(String[] result : results){
if(result != null && result.length == 2){
if(!returnMap.containsKey(result[0])){
returnMap.put(result[0], new HashSet<String>());
}
returnMap.get(result[0]).add(result[1]);
}
}
}
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < nodeIds.length);
return returnMap;
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
/**
* DAC-40 Highlight Inactive Courses in site search
* requires the job "InactiveCoursesJob" attached in the jira
*/
public List<String> findActiveSites(String[] siteIds){
List<String> returnList = new ArrayList<String>();
if(siteIds == null || siteIds.length == 0){
return returnList;
}
try{
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > siteIds.length){
subArraySize = (siteIds.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(siteIds, subArrayIndex, subArrayIndex + subArraySize);
String query = getStatement("select.activeSites");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query = query.replace("(?)", inParams);
List<String> results = (List<String>) getJdbcTemplate().query(query, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("SITE_ID");
}
});
if(results != null){
returnList.addAll(results);
}
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < siteIds.length);
return returnList;
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
public void removeAnonAndAuthRoles(String[] siteRefs){
try{
if(siteRefs == null || siteRefs.length == 0){
return;
}
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > siteRefs.length){
subArraySize = (siteRefs.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(siteRefs, subArrayIndex, subArrayIndex + subArraySize);
String query1 = getStatement("delete.anon.auth.roles");
String query2 = getStatement("delete.anon.auth.permissions");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query1 = query1.replace("(?)", inParams);
query2 = query2.replace("(?)", inParams);
getJdbcTemplate().update(query1);
getJdbcTemplate().update(query2);
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < siteRefs.length);
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
}
}
public void copyRole(String fromRealm, String fromRole, String[] toRealm, String toRole){
if(toRealm == null || toRealm.length == 0){
return;
}
try{
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > toRealm.length){
subArraySize = (toRealm.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(toRealm, subArrayIndex, subArrayIndex + subArraySize);
String query1 = getStatement("insert.copyrole");
String query2 = getStatement("insert.copyroledesc");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query1 = query1.replace("(?)", inParams);
query2 = query2.replace("(?)", inParams);
getJdbcTemplate().update(query1, new Object[]{fromRealm, fromRole, toRole});
getJdbcTemplate().update(query2, new Object[]{toRole});
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < toRealm.length);
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
}
}
public List<String> getDelegatedAccessUsers(){
try{
return getJdbcTemplate().query(getStatement("select.delegatedaccess.user"), new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("userId");
}
});
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
public List<String> getSitesWithDelegatedAccessTool(String[] siteIds){
try{
List<String> returnList = new ArrayList<String>();
if(siteIds == null || siteIds.length == 0){
return returnList;
}
int subArrayIndex = 0;
do{
int subArraySize = ORACLE_IN_CLAUSE_SIZE_LIMIT;
if(subArrayIndex + subArraySize > siteIds.length){
subArraySize = (siteIds.length - subArrayIndex);
}
String[] subSiteRefs = Arrays.copyOfRange(siteIds, subArrayIndex, subArrayIndex + subArraySize);
String query = getStatement("select.delegatedaccess.user.hasworkspacetool");
String inParams = "(";
for(int i = 0; i < subSiteRefs.length; i++){
inParams += "'" + subSiteRefs[i].replace("'", "''") + "'";
if(i < subSiteRefs.length - 1){
inParams += ",";
}
}
inParams += ")";
query = query.replace("(?)", inParams);
List<String> results = (List<String>) getJdbcTemplate().query(query, new RowMapper() {
public Object mapRow(ResultSet resultSet, int i) throws SQLException {
return resultSet.getString("SITE_ID");
}
});
if(results != null){
returnList.addAll(results);
}
subArrayIndex = subArrayIndex + subArraySize;
}while(subArrayIndex < siteIds.length);
return returnList;
}catch (DataAccessException ex) {
log.error("Error executing query: " + ex.getClass() + ":" + ex.getMessage(), ex);
return null;
}
}
}