Java tutorial
/* * 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.api.service; import nl.surfnet.coin.api.GroupProviderConfiguration; import nl.surfnet.coin.api.client.OpenConextJsonParser; import nl.surfnet.coin.api.client.domain.*; import nl.surfnet.coin.teams.domain.GroupProvider; import nl.surfnet.coin.teams.domain.GroupProviderType; import nl.surfnet.coin.teams.util.GroupProviderPropertyConverter; import org.apache.commons.beanutils.BeanComparator; import org.codehaus.jackson.type.TypeReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.io.IOException; import java.util.*; import java.util.Map.Entry; @Component(value = "mockService") public class MockServiceImpl implements PersonService, GroupService, ConfigurableGroupProvider, GroupProviderConfiguration { private Logger LOG = LoggerFactory.getLogger(MockServiceImpl.class); private static final String GROUP_PROVIDERS_CONFIGURATION_JSON = "json/group-providers-configuration.json"; /** * isActive means: instrumented by the public methods. * If active, only persons and groups are returned that are added by the add** methods. * If not active, a file lookup (json files) will be done instead. * Reset by calling {@link MockServiceImpl#reset()} */ private static boolean isActive; private static long sleepMilliseconds; private final static String JSON_PATH = "json/%s-%s.json"; private final static String FALLBACK = "fallback"; private OpenConextJsonParser parser = new OpenConextJsonParser(); private static Map<String, Person> PERSONS_IN_MEMORY = new HashMap<String, Person>(); private static Map<String, Group20> GROUPS_IN_MEMORY = new HashMap<String, Group20>(); private static Map<String, List<String>> MEMBERSHIPS_IN_MEMORY = new HashMap<String, List<String>>(); @Override public PersonEntry getPerson(String userId, String loggedInUser, String spEntityId) { if (isActive()) { return getPreparedPerson(userId); } /* * Strip all characters that might cause problems in filenames. e.g.: * urn:collab:person:test.surfguest.nl:foo becomes: * urn_collab_person_test.surfguest.nl_foo */ String userIdStripped = userId.replaceAll("[^0-9a-zA-Z_.-]", "_"); final String filename = String.format(JSON_PATH, userIdStripped, "person"); LOG.debug("filename: {}", filename); ClassPathResource pathResource = new ClassPathResource(filename); if (!pathResource.exists()) { pathResource = new ClassPathResource(String.format(JSON_PATH, FALLBACK, "person")); } try { return parser.parsePerson(pathResource.getInputStream()); } catch (IOException e) { throw new RuntimeException(e); } } private PersonEntry getPreparedPerson(String userId) { PersonEntry personEntry = new PersonEntry(); Person person = PERSONS_IN_MEMORY.get(userId); if (person != null) { personEntry.setEntry(person); personEntry.setTotalResults(1); } return personEntry; } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.service.PersonService#getGroupMembers(java.lang.String, * java.lang.String) */ @Override public GroupMembersEntry getGroupMembers(String groupId, String onBehalfOf, String spEntityId, Integer count, Integer startIndex, String sortBy) { if (isActive()) { return getPreparedGroupMembers(groupId); } ClassPathResource pathResource = new ClassPathResource(String.format(JSON_PATH, groupId, "teammembers")); if (!pathResource.exists()) { pathResource = new ClassPathResource(String.format(JSON_PATH, FALLBACK, "teammembers")); } try { GroupMembersEntry entry = parser.parseTeamMembers(pathResource.getInputStream()); processQueryOptions(entry, count, startIndex, sortBy, entry.getEntry()); return entry; } catch (IOException e) { throw new RuntimeException(e); } } /** * A no-op implementation that simply returns the same list (a new one actually, by contract) */ @Override public List<Person> enforceArp(String spEntityId, List<Person> persons) { return new ArrayList<Person>(persons); } private GroupMembersEntry getPreparedGroupMembers(String groupId) { GroupMembersEntry entry = new GroupMembersEntry(); List<String> memberKeys = MEMBERSHIPS_IN_MEMORY.get(groupId); List<Person> members = new ArrayList<Person>(); if (!CollectionUtils.isEmpty(memberKeys)) { for (String id : memberKeys) { members.add(PERSONS_IN_MEMORY.get(id)); } } entry.setEntry(members); entry.setTotalResults(members.size()); return entry; } /* * (non-Javadoc) * * @see nl.surfnet.coin.api.service.GroupService#getGroups(java.lang.String, * java.lang.String) */ @Override public GroupEntry getGroups(String userId, String onBehalfOf, Integer count, Integer startIndex, String sortBy) { ClassPathResource pathResource = new ClassPathResource(String.format(JSON_PATH, userId, "groups")); if (!pathResource.exists()) { pathResource = new ClassPathResource(String.format(JSON_PATH, FALLBACK, "groups")); } try { return parser.parseGroups(pathResource.getInputStream()); } catch (IOException e) { throw new RuntimeException(e); } } private Group20Entry getPreparedGroups20(String userId) { Group20Entry result = new Group20Entry(); Set<Entry<String, List<String>>> entrySet = MEMBERSHIPS_IN_MEMORY.entrySet(); List<Group20> groups20 = new ArrayList<Group20>(); for (Entry<String, List<String>> entry : entrySet) { if (entry.getValue().contains(userId)) { groups20.add(GROUPS_IN_MEMORY.get(entry.getKey())); } } result.setTotalResults(groups20.size()); result.setEntry(groups20); return result; } private Group20Entry getPreparedGroup20(String groupId) { Group20Entry result = new Group20Entry(new ArrayList<Group20>()); Set<Entry<String, Group20>> entrySet = GROUPS_IN_MEMORY.entrySet(); for (Entry<String, Group20> entry : entrySet) { if (entry.getValue().getId().equals(groupId)) { result.getEntry().add(entry.getValue()); break; } } result.setTotalResults(result.getEntry().size()); return result; } /* * (non-Javadoc) * * @see nl.surfnet.coin.api.service.GroupService#getGroups20(java.lang.String, * java.lang.String) */ @Override public Group20Entry getGroups20(String userId, String onBehalfOf, Integer count, Integer startIndex, String sortBy) { if (isActive()) { return getPreparedGroups20(userId); } ClassPathResource pathResource = new ClassPathResource(String.format(JSON_PATH, userId, "groups20")); if (!pathResource.exists()) { pathResource = new ClassPathResource(String.format(JSON_PATH, FALLBACK, "groups20")); } try { return parser.parseGroups20(pathResource.getInputStream()); } catch (IOException e) { throw new RuntimeException(e); } } @Override public GroupEntry getGroup(String userId, String groupId, String onBehalfOf) { throw new RuntimeException("GetGroup is not supported. Use GroupService#getGroup20"); } @Override public Group20Entry getGroup20(String userId, String groupId, String onBehalfOf) { if (isActive()) { return getPreparedGroup20(groupId); } ClassPathResource pathResource = new ClassPathResource(String.format(JSON_PATH, groupId, "group20")); if (!pathResource.exists()) { pathResource = new ClassPathResource(String.format(JSON_PATH, FALLBACK, "group20")); } try { return parser.parseGroups20(pathResource.getInputStream()); } catch (IOException e) { throw new RuntimeException(e); } } @Override public Group20Entry getGroups20ByIds(String personId, String[] ids, Integer count, Integer startIndex) { throw new UnsupportedOperationException("Not supported in mock mode."); } public boolean isActive() { return isActive && sleep(); } public void setActive(boolean isActive) { MockServiceImpl.isActive = isActive; } public void reset() { PERSONS_IN_MEMORY = new HashMap<String, Person>(); GROUPS_IN_MEMORY = new HashMap<String, Group20>(); MEMBERSHIPS_IN_MEMORY = new HashMap<String, List<String>>(); isActive = false; sleepMilliseconds = 0; } private boolean sleep() { isActive = true; if (sleepMilliseconds != 0) { try { Thread.sleep(sleepMilliseconds); } catch (InterruptedException e) { throw new RuntimeException("InterruptedException in MockService#sleep", e); } } return true; } public void addPerson(Person person) { isActive = true; PERSONS_IN_MEMORY.put(person.getId(), person); } public void addGroup(Group20 group) { isActive = true; GROUPS_IN_MEMORY.put(group.getId(), group); } public void addPersonToGroup(String personId, String groupId) { isActive = true; Person person = PERSONS_IN_MEMORY.get(personId); Group20 group = GROUPS_IN_MEMORY.get(groupId); if (person == null || group == null) { // design decision return; } List<String> members = MEMBERSHIPS_IN_MEMORY.get(groupId); if (members == null) { members = new ArrayList<String>(); } members.add(personId); MEMBERSHIPS_IN_MEMORY.put(groupId, members); } /** * Filter/mangle a result set based on query parameters * * @param parent * the root object; effectively this parameter is altered by setting * the totalResults property * @param count * nr of records to fetch * @param startIndex * the start index * @param sortBy * field to sort by * @param entry * the result list of entries * @return */ @SuppressWarnings("unchecked") protected List<? extends Object> processQueryOptions(AbstractEntry parent, Integer count, Integer startIndex, String sortBy, List<? extends Object> entry) { parent.setTotalResults(entry.size()); if (StringUtils.hasText(sortBy)) { BeanComparator comparator = new BeanComparator(sortBy); Collections.sort(entry, comparator); parent.setSorted(true); } int size = entry.size(); if (startIndex != null && startIndex.intValue() != 0 && startIndex < size) { entry = entry.subList(startIndex, size); parent.setStartIndex(startIndex); } if (count != null && count.intValue() != 0 && count < size) { entry = entry.subList(0, (entry.size() > count) ? count : entry.size()); parent.setItemsPerPage(count); } return entry; } public void sleep(long millSeconds) { isActive = true; sleepMilliseconds = millSeconds; } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#isInternalGroup(java.lang * .String) */ @Override public boolean isInternalGroup(String groupId) { return true; } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#getAllowedGroupProviders * (nl.surfnet.coin.api.GroupProviderConfiguration.Service, java.lang.String, * java.util.List) */ @Override public List<GroupProvider> getAllowedGroupProviders(Service service, String spEntityId, List<GroupProvider> allGroupProviders) { return allGroupProviders; } /* * (non-Javadoc) * * @see nl.surfnet.coin.api.GroupProviderConfiguration#getAllGroupProviders() */ @Override public List<GroupProvider> getAllGroupProviders() { try { List<GroupProvider> groupProviders = parser.getObjectMapper().readValue( new ClassPathResource(GROUP_PROVIDERS_CONFIGURATION_JSON).getInputStream(), new TypeReference<List<GroupProvider>>() { }); return groupProviders; } catch (Exception e) { throw new RuntimeException(e); } } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#isGrouperCallsAllowed(nl * .surfnet.coin.api.GroupProviderConfiguration.Service, java.lang.String, * java.util.List) */ @Override public boolean isCallAllowed(Service service, String spEntityId, GroupProvider groupProvider) { return !groupProvider.isExternalGroupProvider(); } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#getGroupMembersEntry(nl. * surfnet.coin.teams.domain.GroupProvider, java.lang.String, * java.lang.String, int, int) */ @Override public GroupMembersEntry getGroupMembersEntry(GroupProvider groupProvider, String onBehalfOf, String groupId, int limit, int offset) { throw new RuntimeException( "This call is not supported (and should never be called as we don't support external group providers in mock modus)"); } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#getGroup20Entry(nl.surfnet * .coin.teams.domain.GroupProvider, java.lang.String, int, int) */ @Override public Group20Entry getGroup20Entry(GroupProvider groupProvider, String userId, int limit, int offset) { throw new RuntimeException( "This call is not supported (and should never be called as we don't support external group providers in mock modus)"); } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#cutOffUrnPartForGrouper( * java.util.List, java.lang.String) */ @Override public String cutOffUrnPartForGrouper(List<GroupProvider> groupProviders, String groupId) { for (GroupProvider groupProvider : groupProviders) { if (groupProvider.getGroupProviderType().equals(GroupProviderType.GROUPER)) { return GroupProviderPropertyConverter.convertToExternalGroupId(groupId, groupProvider); } } throw new RuntimeException("No Grouper groupProvider present in the list of groupProviders('" + groupProviders + "') so we can't cut off the groupId('" + groupId + "')"); } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#getGroup20(nl.surfnet.coin * .teams.domain.GroupProvider, java.lang.String, java.lang.String) */ @Override public Group20 getGroup20(GroupProvider groupProvider, String userId, String groupId) { throw new RuntimeException( "This call is not supported (and should never be called as we don't support external group providers in mock modus)"); } /* * (non-Javadoc) * * @see * nl.surfnet.coin.api.GroupProviderConfiguration#addUrnPartForGrouper(java * .util.List, nl.surfnet.coin.api.client.domain.Group20Entry) */ @Override public Group20Entry addUrnPartForGrouper(List<GroupProvider> groupProviders, Group20Entry group20Entry) { Assert.notNull(group20Entry, "group20Entry cannot be null."); Group20Entry result = new Group20Entry(new ArrayList<Group20>()); GroupProvider grouper = null; for (GroupProvider groupProvider : groupProviders) { if (groupProvider.getGroupProviderType().equals(GroupProviderType.GROUPER)) { grouper = groupProvider; break; } } if (grouper == null) { throw new RuntimeException("No Grouper groupProvider present in the list of groupProviders('" + groupProviders + "') so we can't add the surfconext urn part"); } for (Group20 group : group20Entry.getEntry()) { String convertToSurfConextGroupId = GroupProviderPropertyConverter .convertToSurfConextGroupId(group.getId(), grouper); group.setId(convertToSurfConextGroupId); result.getEntry().add(group); } return result; } }