/* * Copyright 2012 SURFnet bv, The Netherlands * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.surfnet.coin.teams.service.impl; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import nl.surfnet.coin.api.client.domain.Group20; import nl.surfnet.coin.api.client.domain.Group20Entry; import nl.surfnet.coin.api.client.domain.GroupMembersEntry; import nl.surfnet.coin.api.client.domain.Person; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.Transformer; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowCallbackHandler; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.util.Assert; public class ApiGrouperDaoImpl extends AbstractGrouperDaoImpl implements ApiGrouperDao { private static final Logger LOG = LoggerFactory.getLogger(ApiGrouperDaoImpl.class); private JdbcTemplate jdbcTemplate; /* * http://static.springsource.org/spring/docs/2.5.x/reference/jdbc.html#jdbc-in * -clause */ private NamedParameterJdbcTemplate namedParameterJdbcTemplate; private static final Map<String, String> VALID_SORTS_FOR_TEAM_QUERY; static { VALID_SORTS_FOR_TEAM_QUERY = new HashMap<String, String>(); VALID_SORTS_FOR_TEAM_QUERY.put("id", "name"); VALID_SORTS_FOR_TEAM_QUERY.put("title", "display_name"); VALID_SORTS_FOR_TEAM_QUERY.put("description", "description"); } public Group20Entry findGroup20(String personId, String groupName) { Group20Entry group20Entry; Assert.notNull(personId, "The personId can not be null"); Assert.notNull(groupName, "The groupName can not be null"); try { LOG.debug("Query to grouper database for person '{}' in group '{}'", personId, groupName.toUpperCase()); group20Entry = new Group20Entry(Arrays.asList(jdbcTemplate.queryForObject( SQL_FIND_TEAM_BY_MEMBER_AND_BY_GROUPNAME, new Object[] { personId, groupName.toUpperCase() }, new OpenSocial20GroupRowMapper()))); addRolesToGroups(personId, group20Entry.getEntry()); } catch (EmptyResultDataAccessException ignored) { group20Entry = new Group20Entry(); } return group20Entry; } public Group20Entry findAllGroup20sByMember(String personId, Integer offset, Integer pageSize, String sortBy) { int rowCount = this.jdbcTemplate.queryForInt(SQL_FIND_ALL_TEAMS_BY_MEMBER_ROWCOUNT, personId); List<Group20> groups = new ArrayList<Group20>(); pageSize = correctPageSize(pageSize); offset = correctOffset(offset); try { String sql = formatAllTeamsSQLWithSortByOption(sortBy); groups = jdbcTemplate.query(sql, new Object[] { personId, pageSize, offset }, new OpenSocial20GroupRowMapper()); addRolesToGroups(personId, groups); } catch (EmptyResultDataAccessException e) { } return new Group20Entry(groups, pageSize, offset, sortBy, rowCount); } protected String formatAllTeamsSQLWithSortByOption(String sortBy) { String sql = SQL_FIND_ALL_TEAMS_BY_MEMBER_SORTED; if (!StringUtils.isBlank(sortBy)) { String sortByColumn = null; Set<Entry<String, String>> entrySet = VALID_SORTS_FOR_TEAM_QUERY.entrySet(); for (Entry<String, String> entry : entrySet) { if (entry.getKey().equals(sortBy)) { sortByColumn = entry.getValue(); break; } } Assert.isTrue(!StringUtils.isBlank(sortByColumn), "The only supported sortBy options are (" + VALID_SORTS_FOR_TEAM_QUERY.keySet() + "). Not allowed is '" + sortBy + "'"); sql = String.format(sql, sortByColumn); } else { sql = String.format(sql, "name"); } return sql; } public static class OpenSocial20GroupRowMapper extends GrouperRowMapper<Group20> { @Override public Group20 createObj(String id, String name, String description) { return new Group20(id, name, description); } } private enum Role { Manager, Admin, Member, none } private void addRolesToGroups(String personId, List<Group20> groups) { try { RolesRowCallbackHandler handler = new RolesRowCallbackHandler(); this.jdbcTemplate.query(SQL_ROLES_BY_TEAMS, new Object[] { personId }, handler); Map<String, Role> roles = handler.roles; for (Group20 group : groups) { Role role = roles.get(group.getId()); role = (role == null ? Role.Member : role); group.setVoot_membership_role(role.name().toLowerCase()); } } catch (EmptyResultDataAccessException e) { // this we can ignore } } private class RolesRowCallbackHandler implements RowCallbackHandler { protected Map<String, Role> roles; public RolesRowCallbackHandler() { super(); this.roles = new HashMap<String, Role>(); } @Override public void processRow(ResultSet rs) throws SQLException { String groupName = rs.getString("groupname"); String permission = rs.getString("fieldname"); /* * If the permission equals 'admins' then we have an Role.Admin, else we * have a role Role.Manager, but we must not overwrite a previous * Role.Admin */ Role role = roles.get(groupName); if (!Role.Admin.equals(role)) { roles.put(groupName, permission.equals("admins") ? Role.Admin : Role.Manager); } } } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } /* * (non-Javadoc) * * @see * nl.surfnet.coin.teams.service.impl.ApiGrouperDao#findAllMembers(java.lang * .String, int, int) */ @Override public GroupMembersEntry findAllMembers(String groupId, Integer offset, Integer pageSize) { List<Person> persons = new ArrayList<Person>(); pageSize = correctPageSize(pageSize); offset = correctOffset(offset); try { RowMapper<Person> mapper = new RowMapper<Person>() { @Override public Person mapRow(ResultSet rs, int rowNum) throws SQLException { Person person = new Person(); person.setId(rs.getString(1)); return person; } }; persons = jdbcTemplate.query(SQL_MEMBERS_BY_TEAM, new Object[] { groupId, pageSize, offset }, mapper); if (CollectionUtils.isNotEmpty(persons)) { addPersonRolesToGroup(persons, groupId); } } catch (EmptyResultDataAccessException e) { // ignore as we have a sensible default } return new GroupMembersEntry(persons); } @Override public Group20Entry findGroups20ByIds(String personId, String[] groupIds, Integer pageSize, Integer offset) { Map<String, Object> params = new HashMap<String, Object>(); params.put("groupId", Arrays.asList(groupIds)); List<Group20> groups = new ArrayList<Group20>(); pageSize = correctPageSize(pageSize); offset = correctOffset(offset); params.put("limit", pageSize); params.put("offset", offset); try { String sql = SQL_FIND_TEAMS_BY_GROUPIDS; groups = namedParameterJdbcTemplate.query(sql, params, new OpenSocial20GroupRowMapper()); addRolesToGroups(personId, groups); } catch (EmptyResultDataAccessException e) { } // FIXME: rowCount != groups.size() maar aparte query voor rowcount (query bestaat al: SQL_FIND_TEAMS_BY_GROUPIDS_ROWCOUNT) return new Group20Entry(groups, pageSize, offset, null, groups.size()); } @SuppressWarnings("unchecked") private void addPersonRolesToGroup(Collection<Person> persons, String groupId) { try { RolesMembersRowCallbackHandler handler = new RolesMembersRowCallbackHandler(); Collection<String> personIds = CollectionUtils.collect(persons, new Transformer() { @Override public Object transform(Object input) { return ((Person) input).getId(); } }); Map<String, Object> params = new HashMap<String, Object>(); params.put("groupId", groupId); params.put("identifiers", personIds); namedParameterJdbcTemplate.query(SQL_ROLES_BY_TEAM_AND_MEMBERS, params, handler); for (Person person : persons) { Role role = handler.roles.get(person.getId()); role = (role == null ? Role.Member : role); person.setVoot_membership_role(role.name().toLowerCase()); } } catch (EmptyResultDataAccessException e) { // this we can ignore } } private class RolesMembersRowCallbackHandler extends RolesRowCallbackHandler { @Override public void processRow(ResultSet rs) throws SQLException { String personName = rs.getString("subject_id"); String permission = rs.getString("fieldname"); Role role = roles.get(personName); if (!Role.Admin.equals(role)) { roles.put(personName, permission.equals("admins") ? Role.Admin : Role.Manager); } } } /** * @param namedParameterJdbcTemplate * the namedParameterJdbcTemplate to set */ public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) { this.namedParameterJdbcTemplate = namedParameterJdbcTemplate; } }