Java tutorial
/******************************************************************************* * Copyright (c) 2013 Lectorius, Inc. * Authors: * Vijay Pandurangan (vijayp@mitro.co) * Evan Jones (ej@mitro.co) * Adam Hilss (ahilss@mitro.co) * * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * You can contact the authors at inbound@mitro.co. *******************************************************************************/ /** * */ package co.mitro.core.servlets; import java.io.IOException; import java.sql.SQLException; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.annotation.WebServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import co.mitro.core.accesscontrol.AuthenticatedDB; import co.mitro.core.exceptions.MitroServletException; import co.mitro.core.server.data.DBGroup; import co.mitro.core.server.data.DBIdentity; import co.mitro.core.server.data.DBPendingGroup; import co.mitro.core.server.data.RPC; import co.mitro.core.server.data.RPC.AddPendingGroupRequest.MemberList; import co.mitro.core.server.data.RPC.EditGroupRequest; import co.mitro.core.server.data.RPC.GetPendingGroupApprovalsRequest; import co.mitro.core.server.data.RPC.GetPendingGroupApprovalsResponse.PendingGroupApproval; import co.mitro.core.server.data.RPC.GroupDiff; import co.mitro.core.server.data.RPC.GroupDiff.GroupModificationType; import co.mitro.core.server.data.RPC.MitroRPC; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; /** * @author vijayp * */ @WebServlet("/api/GetPendingGroups") public class GetPendingGroupApprovals extends MitroServlet { /** * */ private static final long serialVersionUID = 7257988672701779890L; private static final Logger logger = LoggerFactory.getLogger(GetPendingGroupApprovals.class); /* * (non-Javadoc) * * @see * co.mitro.core.servlets.MitroServlet#processCommand(co.mitro.core.server * .data.DBIdentity, java.lang.String, co.mitro.core.server.Manager) */ @SuppressWarnings("deprecation") @Override protected MitroRPC processCommand(MitroRequestContext context) throws IOException, SQLException, MitroServletException { GetPendingGroupApprovalsRequest in = gson.fromJson(context.jsonRequest, GetPendingGroupApprovalsRequest.class); RPC.GetPendingGroupApprovalsResponse out = new RPC.GetPendingGroupApprovalsResponse(); out.pendingAdditionsAndModifications = Lists.newArrayList(); out.pendingDeletions = Lists.newArrayList(); out.diffs = Collections.emptyMap(); out.newOrgMembers = Collections.emptyList(); out.deletedOrgMembers = Collections.emptyList(); AuthenticatedDB userDb = AuthenticatedDB.deprecatedNew(context.manager, context.requestor); Set<DBGroup> orgs = userDb.getOrganizations(); if (orgs.isEmpty()) { logger.warn("ignoring request from user who is not a member of any organizations"); return out; } else { assert orgs.size() == 1; } final DBGroup org = orgs.iterator().next(); assert (userDb.isOrganizationAdmin(org.getId())); List<DBPendingGroup> pendingDBGroups = context.manager.pendingGroupDao.queryForEq(DBPendingGroup.OWNING_ORG, org.getId()); Map<String, PendingGroupApproval> pendingGroups = Maps.newHashMap(); String nonce = null; String scope = null; for (DBPendingGroup databasePendingGroup : pendingDBGroups) { PendingGroupApproval pendingGroupOutput = new PendingGroupApproval(); if (nonce == null) { nonce = databasePendingGroup.getSyncNonce(); } else { assert (nonce.equals(databasePendingGroup.getSyncNonce())) : "only one nonce per sync data allowed " + nonce + " " + databasePendingGroup.getSyncNonce(); } // TODO: support multiple scopes per org by merging groups from multiple scopes. if (scope == null) { scope = databasePendingGroup.getScope(); } else { assert scope.equals(databasePendingGroup.getScope()) : "non-unique scope detected: " + scope + ", " + databasePendingGroup.getScope(); } databasePendingGroup.fillPendingGroup(pendingGroupOutput); pendingGroups.put(pendingGroupOutput.groupName, pendingGroupOutput); } out.syncNonce = nonce; Map<String, DBGroup> existingGroups = Maps.newHashMap(); Map<String, GroupDiff> diffs = Maps.newHashMap(); Map<String, MemberList> groupNameToMemberListMap = Maps.newHashMap(); AddPendingGroupServlet.calculatePendingGroupDiffs(context, pendingGroups.values(), org, existingGroups, diffs, groupNameToMemberListMap, scope); for (String groupName : Sets.union(pendingGroups.keySet(), diffs.keySet())) { if (pendingGroups.containsKey(groupName)) { if (!diffs.containsKey(groupName)) { continue; } final PendingGroupApproval groupApprovalOut = pendingGroups.get(groupName); final GroupDiff gd = diffs.get(groupName); assert (!gd.groupModification.equals(GroupModificationType.IS_DELETED)); if (gd.groupModification.equals(GroupModificationType.IS_NEW)) { groupApprovalOut.matchedGroup = null; } else { final DBGroup matchedGroup = existingGroups.get(groupName); groupApprovalOut.matchedGroup = new EditGroupRequest(); GetGroup.fillEditGroupRequest(context.manager, matchedGroup, groupApprovalOut.matchedGroup, in.deviceId); } out.pendingAdditionsAndModifications.add(groupApprovalOut); } else { assert (diffs.containsKey(groupName)); final GroupDiff gd = diffs.get(groupName); assert (gd.groupModification.equals(GroupModificationType.IS_DELETED)); // otherwise it should have been handled above. EditGroupRequest groupToDelete = new EditGroupRequest(); GetGroup.fillEditGroupRequest(context.manager, existingGroups.get(gd.groupName), groupToDelete, in.deviceId); out.pendingDeletions.add(groupToDelete); } } if (!diffs.isEmpty()) { // TODO: eventually pull this out of a special ALL group that ought to be synced. Set<String> allUserNames = Sets.newHashSet(); for (MemberList ml : groupNameToMemberListMap.values()) { allUserNames.addAll(ml.memberList); } // see which users we need to add to the org. Set<Integer> orgUserIds = MutateOrganization.getMemberIdsAndPrivateGroupIdsForOrg(context.manager, org) .keySet(); Set<String> existingOrgMembers = DBIdentity.getUserNamesFromIds(context.manager, orgUserIds); out.newOrgMembers = Lists.newArrayList(Sets.difference(allUserNames, existingOrgMembers)); // TODO: if none of the groups that are synced is an ALL group, // i.e. we're syncing a subset of the org, this will suggest // deleting most org members, which is not good. We need a better // solution for this. out.deletedOrgMembers = Lists.newArrayList(Sets.difference(existingOrgMembers, allUserNames)); } else { out.deletedOrgMembers = Collections.emptyList(); out.newOrgMembers = Collections.emptyList(); } out.diffs = diffs; out.orgId = org.getId(); assert (out.diffs.size() == (out.pendingAdditionsAndModifications.size() + out.pendingDeletions.size())); return out; } }