SpaceRestServices.java
package org.exoplatform.platform.common.rest.services.SuggestSpacesPortlet;
import org.exoplatform.common.http.HTTPStatus;
import org.exoplatform.commons.utils.ListAccess;
import org.exoplatform.container.ExoContainer;
import org.exoplatform.container.ExoContainerContext;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.rest.impl.RuntimeDelegateImpl;
import org.exoplatform.services.rest.resource.ResourceContainer;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.manager.RelationshipManager;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Random;
import java.util.TreeMap;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.RuntimeDelegate;
@Path("/homepage/intranet/spaces/")
@Produces("application/json")
public class SpaceRestServices implements ResourceContainer {
private static final Log LOG = ExoLogger.getLogger(SpaceRestServices.class);
private static final CacheControl cacheControl;
private static final String SPACE_NAME = "name";
private static final String SPACE_ID = "spaceId";
private static final String SPACE_DISPLAY_NAME = "displayName";
private static final String SPACE_URL = "spaceUrl";
private static final String SPACE_AVATAR_URL = "spaceAvatarUrl";
private static final String SPACE_REGISTRATION = "registration";
private static final String SPACE_MEMBERS = "members";
private static final String SPACE_PRIVACY = "privacy";
private static final String NUMBER = "number";
private static final String SPACE_CREATED_DATE = "createdDate";
private static final String ITEMS ="items";
static {
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
cacheControl = new CacheControl();
cacheControl.setNoCache(true);
cacheControl.setNoStore(true);
}
// The owner of the rest component
private final ExoContainer container;
public SpaceRestServices(ExoContainerContext ctx) {
this.container = ctx.getContainer();
}
@GET
@Path("suggestions")
public Response getSuggestions(@Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
JSONArray jsonArray = new JSONArray();
JSONObject jsonGlobal = new JSONObject();
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
ListAccess<Space> suggestedSpacesLA = spaceService.getPublicSpacesWithListAccess(userId);
// new create system with no spaces
int size = suggestedSpacesLA.getSize();
if (size == 0) {
jsonGlobal.put(ITEMS,jsonArray);
jsonGlobal.put("noConnections", 0);
jsonGlobal.put("username", userId);
return Response.ok(jsonGlobal.toString(), MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
}
IdentityManager identityManager = (IdentityManager) container.getComponentInstanceOfType(IdentityManager.class);
RelationshipManager relationshipManager = (RelationshipManager) container.getComponentInstanceOfType(RelationshipManager.class);
Identity identity = identityManager.getOrCreateIdentity(OrganizationIdentityProvider.NAME, userId, false);
ListAccess<Identity> connectionsLA = relationshipManager.getConnections(identity);
final Map<Space, Integer> spacesWithMemberNum = new HashMap<Space, Integer>();
int maxConnectionsToLoad = 100;
int maxSpacesToLoad = 50;
int maxSuggestions = 10;
int totalConnections = connectionsLA.getSize();
Random random = new Random();
Identity[] connections;
if (totalConnections > maxConnectionsToLoad) {
int startIndex = random.nextInt(totalConnections - maxConnectionsToLoad);
connections = connectionsLA.load(startIndex, maxConnectionsToLoad);
} else {
connections = connectionsLA.load(0, totalConnections);
}
Space[] suggestedSpaces;
if (size > maxSpacesToLoad) {
int startIndex = random.nextInt(size - maxSpacesToLoad);
suggestedSpaces = suggestedSpacesLA.load(startIndex, maxSpacesToLoad);
} else {
suggestedSpaces = suggestedSpacesLA.load(0, size);
}
for (Space space : suggestedSpaces) {
// Skip space when the current user is already a member of
if(spaceService.isMember(space, identity.getRemoteId())) {
continue;
}
for (Identity connector : connections) {
//
if (Space.HIDDEN.equals(space.getVisibility()))
continue;
if (Space.CLOSE.equals(space.getRegistration()))
continue;
if (!spaceService.isMember(space, connector.getRemoteId()))
continue;
if (!spaceService.isIgnored(space, connector.getRemoteId()))
continue;
Integer value = spacesWithMemberNum.get(space);
if (value == null) {
value = new Integer(1);
} else {
value = new Integer(value.intValue() + 1);
}
spacesWithMemberNum.put(space, value);
}
}
if (!spacesWithMemberNum.isEmpty()) {
NavigableMap<Integer, List<Space>> groupByCommonConnections = new TreeMap<Integer, List<Space>>();
// This for loop allows to group the suggestions by total amount of common connections
for (Space space : spacesWithMemberNum.keySet()) {
Integer commonSpaces = spacesWithMemberNum.get(space);
List<Space> spaces = groupByCommonConnections.get(commonSpaces);
if (spaces == null) {
spaces = new ArrayList<Space>();
groupByCommonConnections.put(commonSpaces, spaces);
}
spaces.add(space);
}
int suggestionLeft = maxSuggestions;
// We iterate over the suggestions starting from the suggestions with the highest amount common
// connections
main: for (Integer key : groupByCommonConnections.descendingKeySet()) {
List<Space> spaces = groupByCommonConnections.get(key);
for (Space space : spaces) {
JSONObject json = buildJSONObject(space, key);
jsonArray.put(json);
// We stop once we have enough suggestions
if (--suggestionLeft == 0)
break main;
}
}
} else {
// Propose the last spaces
List<Space> lastSpaces = spaceService.getLastSpaces(10);
for (Space space : lastSpaces) {
if (Space.HIDDEN.equals(space.getVisibility()))
continue;
if (Space.CLOSE.equals(space.getRegistration()))
continue;
if (spaceService.isMember(space, identity.getRemoteId()))
continue;
if (spaceService.isPendingUser(space, identity.getRemoteId()))
continue;
if (spaceService.isInvitedUser(space, identity.getRemoteId()))
continue;
if (spaceService.isIgnored(space, identity.getRemoteId()))
continue;
JSONObject json = buildJSONObject(space, 0);
json.put("username", userId);
jsonArray.put(json);
}
}
jsonGlobal.put(ITEMS,jsonArray);
jsonGlobal.put("noConnections", spacesWithMemberNum.size());
jsonGlobal.put("username", userId);
return Response.ok(jsonGlobal.toString(), MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space invitation rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
private JSONObject buildJSONObject(Space space, int k) throws JSONException {
String avatar = space.getAvatarUrl();
if (avatar == null) {
avatar = "/eXoSkin/skin/images/themes/default/social/skin/ShareImages/UserAvtDefault.png";
}
String spaceType = "";
if (space.getRegistration() == null || space.getRegistration().equals(Space.OPEN)) {
spaceType = "Public";
} else {
spaceType = "Private";
}
JSONObject json = new JSONObject();
json.put(SPACE_NAME, space.getPrettyName());
json.put(SPACE_ID, space.getId());
json.put(SPACE_DISPLAY_NAME, space.getDisplayName());
json.put(SPACE_URL, space.getUrl());
json.put(SPACE_AVATAR_URL, avatar);
json.put(SPACE_REGISTRATION, space.getRegistration());
json.put(SPACE_MEMBERS, space.getMembers() == null ? 0 : space.getMembers().length);
json.put(SPACE_PRIVACY, spaceType);
json.put(NUMBER, k);
json.put(SPACE_CREATED_DATE, space.getCreatedTime());
return json;
}
@GET
@Path("accept/{spaceName}")
public Response accept(@PathParam("spaceName") String spaceName, @Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
if (spaceService.isInvitedUser(spaceService.getSpaceById(spaceName), userId))
spaceService.addMember(spaceService.getSpaceById(spaceName), userId);
return Response.ok("{}", MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space accept rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
@GET
@Path("deny/{spaceName}")
public Response deny(@PathParam("spaceName") String spaceName, @Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
spaceService.removeInvitedUser(spaceService.getSpaceById(spaceName), userId);
return Response.ok("{}", MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space deny rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
@GET
@Path("request/{spaceName}")
public Response request(@PathParam("spaceName") String spaceName, @Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
spaceService.addPendingUser(spaceService.getSpaceById(spaceName), userId);
return Response.ok("{}", MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space deny rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
@GET
@Path("join/{spaceName}")
public Response join(@PathParam("spaceName") String spaceName, @Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
if (spaceService.getSpaceById(spaceName).getRegistration().equals("open"))
spaceService.addMember(spaceService.getSpaceById(spaceName), userId);
return Response.ok("{}", MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space deny rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
@GET
@Path("myspaces")
public Response request(@Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
List<Space> mySpaces = spaceService.getAccessibleSpaces(userId);
JSONArray jsonArray = new JSONArray();
for (Space space : mySpaces) {
JSONObject json = new JSONObject();
json.put(SPACE_NAME, space.getName());
json.put(SPACE_ID, space.getId());
json.put(SPACE_DISPLAY_NAME, space.getDisplayName());
json.put(SPACE_URL, space.getUrl());
json.put(SPACE_MEMBERS, space.getMembers().length);
jsonArray.put(json);
}
return Response.ok(jsonArray.toString(), MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space deny rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
@GET
@Path("public")
public Response getPublicSpaces(@Context SecurityContext sc, @Context UriInfo uriInfo) {
try {
String userId = getUserId(sc, uriInfo);
if (userId == null) {
return Response.status(HTTPStatus.INTERNAL_ERROR).cacheControl(cacheControl).build();
}
SpaceService spaceService = (SpaceService) container.getComponentInstanceOfType(SpaceService.class);
ListAccess<Space> publicSpaces = spaceService.getPublicSpacesWithListAccess(userId);
JSONArray jsonArray = new JSONArray();
Space[] spaces = publicSpaces.load(0, publicSpaces.getSize());
if (spaces != null && spaces.length > 0) {
for (Space space : spaces) {
if (space.getVisibility().equals(Space.HIDDEN))
continue;
if (space.getRegistration().equals(Space.CLOSE))
continue;
JSONObject json = new JSONObject();
json.put(SPACE_NAME, space.getName());
json.put(SPACE_DISPLAY_NAME, space.getDisplayName());
json.put(SPACE_ID, space.getId());
jsonArray.put(json);
}
}
return Response.ok(jsonArray.toString(), MediaType.APPLICATION_JSON).cacheControl(cacheControl).build();
} catch (Exception e) {
LOG.error("Error in space invitation rest service: " + e.getMessage(), e);
return Response.ok("error").cacheControl(cacheControl).build();
}
}
private String getUserId(SecurityContext sc, UriInfo uriInfo) {
try {
return sc.getUserPrincipal().getName();
} catch (NullPointerException e) {
return getViewerId(uriInfo);
} catch (Exception e) {
return null;
}
}
private String getViewerId(UriInfo uriInfo) {
URI uri = uriInfo.getRequestUri();
String requestString = uri.getQuery();
if (requestString == null) return null;
String[] queryParts = requestString.split("&");
for (String queryPart : queryParts) {
if (queryPart.startsWith("opensocial_viewer_id")) {
return queryPart.substring(queryPart.indexOf("=") + 1, queryPart.length());
}
}
return null;
}
}