org.exoplatform.social.service.rest.RestUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.exoplatform.social.service.rest.RestUtils.java

Source

/*
 * Copyright (C) 2003-2013 eXo Platform SAS.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.exoplatform.social.service.rest;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;

import javax.ws.rs.core.MediaType;

import org.apache.commons.lang.ArrayUtils;
import org.exoplatform.commons.utils.CommonsUtils;
import org.exoplatform.services.rest.ApplicationContext;
import org.exoplatform.services.rest.impl.ApplicationContextImpl;
import org.exoplatform.services.security.ConversationState;
import org.exoplatform.social.core.activity.model.ExoSocialActivity;
import org.exoplatform.social.core.identity.model.Identity;
import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.core.identity.provider.OrganizationIdentityProvider;
import org.exoplatform.social.core.identity.provider.SpaceIdentityProvider;
import org.exoplatform.social.core.manager.ActivityManager;
import org.exoplatform.social.core.manager.IdentityManager;
import org.exoplatform.social.core.manager.RelationshipManager;
import org.exoplatform.social.core.relationship.model.Relationship;
import org.exoplatform.social.core.service.LinkProvider;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;

public class RestUtils {

    public static final int DEFAULT_LIMIT = 20;

    public static final int DEFAULT_OFFSET = 0;

    public static final int HARD_LIMIT = 50;

    public static final String USERS_TYPE = "users";

    public static final String USERS_RELATIONSHIP_TYPE = "usersRelationships";

    public static final String USER_ACTIVITY_TYPE = "user";

    public static final String IDENTITIES_TYPE = "identities";

    public static final String SPACES_TYPE = "spaces";

    public static final String SPACES_MEMBERSHIP_TYPE = "spacesMemberships";

    public static final String SPACE_ACTIVITY_TYPE = "space";

    public static final String ACTIVITIES_TYPE = "activities";

    public static final String COMMENTS_TYPE = "comments";

    public static final String LIKES_TYPE = "likes";

    public static final String KEY = "key";

    public static final String VALUE = "value";

    public static final String SUPPORT_TYPE = "json";

    public static final String ADMIN_GROUP = "/platform/administrators";

    /**
     * Get a hash map from an identity in order to build a json object for the rest service
     * 
     * @param identity the provided identity
     * @return a hash map
     */
    public static Map<String, Object> buildEntityFromIdentity(Identity identity, String restPath, String expand) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        Profile profile = identity.getProfile();
        map.put(RestProperties.ID, identity.getId());
        map.put(RestProperties.USER_NAME, identity.getRemoteId());
        if (OrganizationIdentityProvider.NAME.equals(identity.getProviderId())) {
            map.put(RestProperties.FIRST_NAME,
                    profile.getProperty(Profile.FIRST_NAME) != null
                            ? profile.getProperty(Profile.FIRST_NAME).toString()
                            : "");
            map.put(RestProperties.LAST_NAME,
                    profile.getProperty(Profile.LAST_NAME) != null
                            ? profile.getProperty(Profile.LAST_NAME).toString()
                            : "");
            map.put(RestProperties.GENDER, profile.getGender());
            map.put(RestProperties.POSITION, profile.getPosition());
            map.put(RestProperties.FULL_NAME, profile.getFullName());
            map.put(RestProperties.EMAIL, profile.getEmail());
            map.put(RestProperties.HREF,
                    (expand != null && RestProperties.HREF.equals(expand))
                            ? buildEntityFromIdentity(identity, restPath, null)
                            : Util.getRestUrl(USERS_TYPE, identity.getRemoteId(), restPath));
            map.put(RestProperties.PHONES, getSubListByProperties(profile.getPhones(), getPhoneProperties()));
            map.put(RestProperties.EXPERIENCES,
                    getSubListByProperties(
                            (List) (List<Map<String, Object>>) profile.getProperty(Profile.EXPERIENCES),
                            getExperiencesProperties()));
            map.put(RestProperties.IMS, getSubListByProperties(
                    (List<Map<String, String>>) profile.getProperty(Profile.CONTACT_IMS), getImsProperties()));
            map.put(RestProperties.URLS, getSubListByProperties(
                    (List<Map<String, String>>) profile.getProperty(Profile.CONTACT_URLS), getUrlProperties()));
            map.put(RestProperties.AVATAR, profile.getAvatarUrl());
        }
        map.put(RestProperties.DELETED, identity.isDeleted());
        map.put(RestProperties.IDENTITY, Util.getRestUrl(IDENTITIES_TYPE, identity.getId(), restPath));

        updateCachedEtagValue(getEtagValue(profile.getFullName(), profile.getGender(), profile.getPosition(),
                profile.getEmail(), profile.getAvatarUrl()
        // tmpPropertyValues {phones, experience, ims, urls}
        ));
        return map;
    }

    /**
     * Get a hash map from a space in order to build a json object for the rest service
     * 
     * @param space the provided space
     * @param userId the user's remote id
     * @return a hash map
     */
    public static Map<String, Object> buildEntityFromSpace(Space space, String userId, String restPath,
            String expand) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        if (ArrayUtils.contains(space.getMembers(), userId) || isMemberOfAdminGroup()) {
            map.put(RestProperties.ID, space.getId());
            map.put(RestProperties.HREF,
                    (expand != null && RestProperties.HREF.equals(expand))
                            ? buildEntityFromSpace(space, userId, restPath, null)
                            : Util.getRestUrl(SPACES_TYPE, space.getId(), restPath));
            Identity spaceIdentity = CommonsUtils.getService(IdentityManager.class)
                    .getOrCreateIdentity(SpaceIdentityProvider.NAME, space.getPrettyName(), true);
            map.put(RestProperties.IDENTITY,
                    (expand != null && RestProperties.IDENTITY.equals(expand))
                            ? buildEntityFromIdentity(spaceIdentity, restPath, null)
                            : Util.getRestUrl(IDENTITIES_TYPE, spaceIdentity.getId(), restPath));
            map.put(RestProperties.GROUP_ID, space.getGroupId());
            map.put(RestProperties.AVATAR_URL, space.getAvatarUrl());
            map.put(RestProperties.APPLICATIONS, getSpaceApplications(space));
            map.put(RestProperties.MANAGERS, Util.getMembersSpaceRestUrl(space.getId(), true, restPath));
            map.put(RestProperties.MEMBERS, Util.getMembersSpaceRestUrl(space.getId(), false, restPath));
        }
        map.put(RestProperties.DISPLAY_NAME, space.getDisplayName());
        map.put(RestProperties.URL, LinkProvider.getSpaceUri(space.getPrettyName()));
        map.put(RestProperties.VISIBILITY, space.getVisibility());
        map.put(RestProperties.SUBSCRIPTION, space.getRegistration());
        updateCachedEtagValue(getEtagValue(space.getDisplayName(), space.getDescription(), space.getPrettyName(),
                space.getVisibility(), space.getRegistration(), space.getAvatarUrl()));
        return map;
    }

    /**
     * Get a hash map from a space in order to build a json object for the rest service
     * 
     * @param space the provided space
     * @param userId the user's remote id
     * @param type membership type
     * @return a hash map
     */
    public static Map<String, Object> buildEntityFromSpaceMembership(Space space, String userId, String type,
            String restPath, String expand) {
        //
        updateCachedEtagValue(getEtagValue(type));

        Map<String, Object> map = new LinkedHashMap<String, Object>();
        String id = space.getPrettyName() + ":" + userId + ":" + type;
        map.put(RestProperties.ID, id);
        map.put(RestProperties.HREF,
                (expand != null && RestProperties.HREF.equals(expand))
                        ? buildEntityFromSpaceMembership(space, userId, type, restPath, null)
                        : Util.getRestUrl(SPACES_MEMBERSHIP_TYPE, id, restPath));
        map.put(RestProperties.USERS, Util.getRestUrl(USERS_TYPE, userId, restPath));
        map.put(RestProperties.SPACES, Util.getRestUrl(SPACES_TYPE, space.getId(), restPath));
        map.put(RestProperties.ROLE, type);
        map.put(RestProperties.STATUS, "approved");

        return map;
    }

    /**
     * Get a hash map from an activity in order to build a json object for the rest service
     * 
     * @param activity the provided activity
     * @param expand 
     * @return a hash map
     */
    public static Map<String, Object> buildEntityFromActivity(ExoSocialActivity activity, String restPath,
            String expand) {
        Identity poster = CommonsUtils.getService(IdentityManager.class).getIdentity(activity.getPosterId(), true);
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        map.put(RestProperties.ID, activity.getId());
        map.put(RestProperties.HREF,
                (expand != null && RestProperties.HREF.equals(expand))
                        ? buildEntityFromActivity(activity, restPath, null)
                        : Util.getRestUrl(ACTIVITIES_TYPE, activity.getId(), restPath));
        map.put(RestProperties.IDENTITY,
                (expand != null && RestProperties.IDENTITY.equals(expand))
                        ? buildEntityFromIdentity(poster, restPath, null)
                        : Util.getRestUrl(IDENTITIES_TYPE, activity.getPosterId(), restPath));
        map.put(RestProperties.MENTIONS, getActivityMentions(activity, restPath));
        if (activity.isComment()) {
            map.put(RestProperties.BODY, activity.getTitle());
            map.put(RestProperties.POSTER, poster.getRemoteId());
            map.put(RestProperties.ACTIVITY, Util.getRestUrl(ACTIVITIES_TYPE,
                    CommonsUtils.getService(ActivityManager.class).getParentActivity(activity).getId(), restPath));
        } else {
            map.put(RestProperties.BODY, activity.getBody());
            map.put(RestProperties.TITLE, activity.getTitle());
            map.put(RestProperties.OWNER, getActivityOwner(poster, restPath));
            map.put(RestProperties.LINK, activity.getPermaLink());
            map.put(RestProperties.ATTACHMENTS, new ArrayList<String>());
            map.put(RestProperties.TYPE, activity.getType());
            map.put(RestProperties.COMMENTS, Util.getCommentsActivityRestUrl(activity.getId(), restPath));
        }
        map.put(RestProperties.CREATE_DATE, formatDateToISO8601(new Date(activity.getPostedTime())));
        map.put(RestProperties.UPDATE_DATE, formatDateToISO8601(activity.getUpdated()));

        updateCachedLastModifiedValue(activity.getUpdated());

        return map;
    }

    /**
     * Get a hash map from a relationship in order to build a json object for the rest service
     * 
     * @param relationship the provided relationship
     * @return a hash map
     */
    public static Map<String, Object> buildEntityFromRelationship(Relationship relationship, String restPath,
            String expand, boolean isSymetric) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();
        map.put(RestProperties.ID, relationship.getId());
        map.put(RestProperties.HREF,
                (expand != null && RestProperties.HREF.equals(expand))
                        ? buildEntityFromRelationship(relationship, restPath, null, isSymetric)
                        : Util.getRestUrl(USERS_RELATIONSHIP_TYPE, relationship.getId(), restPath));
        map.put(RestProperties.STATUS, relationship.getStatus().name());
        map.put(RestProperties.SENDER,
                (expand != null && RestProperties.SENDER.equals(expand))
                        ? buildEntityFromIdentity(relationship.getSender(), restPath, null)
                        : Util.getRestUrl(USERS_TYPE, relationship.getSender().getRemoteId(), restPath));
        map.put(RestProperties.RECEIVER,
                (expand != null && RestProperties.RECEIVER.equals(expand))
                        ? buildEntityFromIdentity(relationship.getReceiver(), restPath, null)
                        : Util.getRestUrl(USERS_TYPE, relationship.getReceiver().getRemoteId(), restPath));
        if (isSymetric) {
            map.put(RestProperties.SYMETRIC, relationship.isSymetric());
        }
        updateCachedEtagValue(getEtagValue(relationship.getId()));
        return map;
    }

    private static Map<String, String> getActivityOwner(Identity owner, String restPath) {
        Map<String, String> mention = new LinkedHashMap<String, String>();
        mention.put(RestProperties.ID, owner.getId());
        mention.put(RestProperties.HREF, Util.getRestUrl(USERS_TYPE, owner.getRemoteId(), restPath));
        return mention;
    }

    private static List<Map<String, String>> getActivityMentions(ExoSocialActivity activity, String restPath) {
        List<Map<String, String>> mentions = new ArrayList<Map<String, String>>();
        for (String mentionner : activity.getMentionedIds()) {
            String mentionnerId = mentionner.split("@")[0];
            Identity userIdentity = CommonsUtils.getService(IdentityManager.class).getIdentity(mentionnerId, false);
            mentions.add(getActivityOwner(userIdentity, restPath));
        }
        return mentions;
    }

    /**
     * Get the activityStream's information related to the activity.
     * 
     * @param authentiatedUsed the viewer
     * @param activity
     * @param target the owner of the stream that we want to display
     * @return activityStream object, null if the viewer has no permission to view activity
     */
    public static Map<String, String> getActivityStream(ExoSocialActivity activity, Identity authentiatedUsed) {
        Map<String, String> as = new LinkedHashMap<String, String>();
        Identity owner = CommonsUtils.getService(IdentityManager.class)
                .getOrCreateIdentity(OrganizationIdentityProvider.NAME, activity.getStreamOwner(), true);
        if (owner != null) { //case of user activity
            Relationship relationship = CommonsUtils.getService(RelationshipManager.class).get(authentiatedUsed,
                    owner);
            if (!authentiatedUsed.getId().equals(activity.getPosterId()) //the viewer is not the poster
                    && !authentiatedUsed.getRemoteId().equals(activity.getStreamOwner()) //the viewer is not the owner
                    && (relationship == null || !relationship.getStatus().equals(Relationship.Type.CONFIRMED)) //the viewer has no relationship with the given user
                    && !isMemberOfAdminGroup()) { //current user is not an administrator  
                return null;
            }
            as.put(RestProperties.TYPE, USER_ACTIVITY_TYPE);
        } else { //case of space activity
            owner = CommonsUtils.getService(IdentityManager.class).getOrCreateIdentity(SpaceIdentityProvider.NAME,
                    activity.getStreamOwner(), true);
            Space space = CommonsUtils.getService(SpaceService.class).getSpaceByPrettyName(owner.getRemoteId());
            if (!CommonsUtils.getService(SpaceService.class).isMember(space, authentiatedUsed.getRemoteId())) { //the viewer is not member of space
                return null;
            }
            as.put(RestProperties.TYPE, SPACE_ACTIVITY_TYPE);
        }
        as.put(RestProperties.ID, owner.getRemoteId());
        return as;
    }

    private static List<Map<String, String>> getSpaceApplications(Space space) {
        List<Map<String, String>> spaceApplications = new ArrayList<Map<String, String>>();
        String installedApps = space.getApp();
        if (installedApps != null) {
            String[] appStatuses = installedApps.split(",");
            for (String appStatus : appStatuses) {
                Map<String, String> app = new LinkedHashMap<String, String>();
                String[] apps = appStatus.split(":");
                app.put(RestProperties.ID, apps[0]);
                app.put(RestProperties.DISPLAY_NAME, apps.length > 1 ? apps[1] : "");
                spaceApplications.add(app);
            }
        }
        return spaceApplications;
    }

    private static List<Map<String, Object>> getSubListByProperties(List<Map<String, String>> sources,
            Map<String, String> properties) {
        List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
        if (sources == null || sources.size() == 0) {
            return results;
        }
        for (Map<String, String> map : sources) {
            if (map.isEmpty())
                continue;
            Map<String, Object> result = new LinkedHashMap<String, Object>();
            for (Entry<String, String> property : properties.entrySet()) {
                result.put(property.getKey(), map.get(property.getValue()));
            }
            results.add(result);
        }

        return results;
    }

    private static Map<String, String> getPhoneProperties() {
        Map<String, String> properties = new LinkedHashMap<String, String>();
        properties.put(RestProperties.PHONE_TYPE, KEY);
        properties.put(RestProperties.PHONE_NUMBER, VALUE);
        return properties;
    }

    private static Map<String, String> getImsProperties() {
        Map<String, String> properties = new LinkedHashMap<String, String>();
        properties.put(RestProperties.IM_TYPE, KEY);
        properties.put(RestProperties.IM_ID, VALUE);
        return properties;
    }

    private static Map<String, String> getUrlProperties() {
        Map<String, String> properties = new LinkedHashMap<String, String>();
        properties.put(RestProperties.URL, VALUE);
        return properties;
    }

    private static Map<String, String> getExperiencesProperties() {
        Map<String, String> properties = new LinkedHashMap<String, String>();
        properties.put(RestProperties.COMPANY, Profile.EXPERIENCES_COMPANY);
        properties.put(RestProperties.DESCRIPTION, Profile.EXPERIENCES_DESCRIPTION);
        properties.put(RestProperties.POSITION, Profile.EXPERIENCES_POSITION);
        properties.put(RestProperties.SKILLS, Profile.EXPERIENCES_SKILLS);
        properties.put(RestProperties.IS_CURRENT, Profile.EXPERIENCES_IS_CURRENT);
        properties.put(RestProperties.START_DATE, Profile.EXPERIENCES_START_DATE);
        properties.put(RestProperties.END_DATE, Profile.EXPERIENCES_END_DATE);
        return properties;
    }

    private static String formatDateToISO8601(Date date) {
        TimeZone tz = TimeZone.getTimeZone("UTC");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'");
        df.setTimeZone(tz);
        return df.format(date);
    }

    private static void updateCachedEtagValue(int etagValue) {
        ApplicationContext ac = ApplicationContextImpl.getCurrent();
        Map<String, String> properties = ac.getProperties();
        ConcurrentHashMap<String, String> props = new ConcurrentHashMap<String, String>(properties);

        if (props.containsKey(RestProperties.ETAG)) {
            props.remove(RestProperties.ETAG);
        }

        if (props.containsKey(RestProperties.UPDATE_DATE)) {
            props.remove(RestProperties.UPDATE_DATE);
        }

        ac.setProperty(RestProperties.ETAG, String.valueOf(etagValue));
        ApplicationContextImpl.setCurrent(ac);
    }

    private static void updateCachedLastModifiedValue(Date lastModifiedDate) {
        ApplicationContext ac = ApplicationContextImpl.getCurrent();
        Map<String, String> properties = ac.getProperties();
        ConcurrentHashMap<String, String> props = new ConcurrentHashMap<String, String>(properties);

        if (props.containsKey(RestProperties.UPDATE_DATE)) {
            props.remove(RestProperties.UPDATE_DATE);
        }

        if (props.containsKey(RestProperties.ETAG)) {
            props.remove(RestProperties.ETAG);
        }

        ac.setProperty(RestProperties.UPDATE_DATE, String.valueOf(lastModifiedDate.getTime()));
        ApplicationContextImpl.setCurrent(ac);
    }

    private static int getEtagValue(String... properties) {
        final int prime = 31;
        int result = 0;

        for (String prop : properties) {
            if (prop != null) {
                result = prime * result + prop.hashCode();
            }
        }

        return result;
    }

    /**
     * Gets the json media type
     * 
     * @return a media type
     */
    public static MediaType getJsonMediaType() {
        return Util.getMediaType(SUPPORT_TYPE, new String[] { SUPPORT_TYPE });
    }

    /**
     * Check if the authenticated user is a member of the admin group
     * 
     * @return
     */
    public static boolean isMemberOfAdminGroup() {
        return ConversationState.getCurrent().getIdentity().isMemberOf(ADMIN_GROUP);
    }
}