org.eurekastreams.server.service.opensocial.spi.ActivityServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.eurekastreams.server.service.opensocial.spi.ActivityServiceImpl.java

Source

/*
 * Copyright (c) 2009-2010 Lockheed Martin Corporation
 *
 * 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 org.eurekastreams.server.service.opensocial.spi;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.Future;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.common.util.ImmediateFuture;
import org.apache.shindig.protocol.ProtocolException;
import org.apache.shindig.protocol.RestfulCollection;
import org.apache.shindig.social.core.model.ActivityImpl;
import org.apache.shindig.social.opensocial.model.Activity;
import org.apache.shindig.social.opensocial.spi.ActivityService;
import org.apache.shindig.social.opensocial.spi.CollectionOptions;
import org.apache.shindig.social.opensocial.spi.GroupId;
import org.apache.shindig.social.opensocial.spi.UserId;
import org.eurekastreams.commons.actions.TaskHandlerAction;
import org.eurekastreams.commons.actions.context.Principal;
import org.eurekastreams.commons.actions.context.service.ServiceActionContext;
import org.eurekastreams.commons.actions.service.ServiceAction;
import org.eurekastreams.commons.actions.service.TaskHandlerServiceAction;
import org.eurekastreams.commons.logging.LogFactory;
import org.eurekastreams.commons.server.service.ActionController;
import org.eurekastreams.server.action.principal.OpenSocialPrincipalPopulator;
import org.eurekastreams.server.action.request.opensocial.GetUserActivitiesRequest;
import org.eurekastreams.server.action.request.stream.PostActivityRequest;
import org.eurekastreams.server.domain.EntityType;
import org.eurekastreams.server.domain.GadgetDefinition;
import org.eurekastreams.server.domain.GeneralGadgetDefinition;
import org.eurekastreams.server.domain.gadgetspec.GadgetMetaDataDTO;
import org.eurekastreams.server.domain.stream.ActivityDTO;
import org.eurekastreams.server.domain.stream.ActivityVerb;
import org.eurekastreams.server.domain.stream.BaseObjectType;
import org.eurekastreams.server.domain.stream.StreamEntityDTO;
import org.eurekastreams.server.persistence.DomainEntityMapper;
import org.eurekastreams.server.persistence.GadgetDefinitionMapper;
import org.eurekastreams.server.service.opensocial.gadgets.spec.GadgetMetaDataFetcher;

import com.google.inject.Inject;
import com.google.inject.name.Named;

/**
 * This class provides the implementation of the ActivityService interface for Shindig.
 *
 */
public class ActivityServiceImpl implements ActivityService {
    /**
     * Logger.
     */
    private final Log log = LogFactory.make();

    /**
     * Action that gets a specified set of activities for a specified user.
     */
    private final ServiceAction getUserActivitiesAction;

    /**
     * Action that deletes a specified set of activities for a specified user.
     */
    private final TaskHandlerAction deleteUserActivities;

    /**
     * Instance of the {@link ActionController} for this class.
     */
    private final ActionController serviceActionController;

    /**
     * Instance of the {@link OpenSocialPrincipalPopulator} for this class.
     */
    private final OpenSocialPrincipalPopulator openSocialPrincipalPopulator;

    /**
     * Instance of the {@link TaskHandlerServiceAction} for this class.
     */
    private final TaskHandlerServiceAction postActivityAction;

    /** For getting gadget definition (in order to get name). */
    private final DomainEntityMapper<GadgetDefinition> gadgetDefinitionMapper;

    /** For getting gadget name. */
    private final GadgetMetaDataFetcher gadgetMetaDataFetcher;

    /**
     * Basic constructor for the PersonService implementation.
     *
     * @param inGetUserActivitiesAction
     *            the action to get a specified set of activities for a specified user.
     * @param inDeleteActivitiesAction
     *            the action to deleted a specified set of activities for a specified user.
     * @param inServiceActionController
     *            - instance of the {@link ActionController} used to execute the actions.
     * @param inOpenSocialPrincipalPopulator
     *            - instance of the {@link OpenSocialPrincipalPopulator} used to retrieve a Principal object based on
     *            the opensocial id.
     * @param inPostActivityAction
     *            the action to create an activity.
     * @param inGadgetDefinitionMapper
     *            Mapper to fetch gadget definitions (for looking up title).
     * @param inGadgetMetaDataFetcher
     *            Used to fetch gadget metadata (for looking up title).
     */
    @Inject
    public ActivityServiceImpl(@Named("getUserActivities") final ServiceAction inGetUserActivitiesAction,
            @Named("deleteUserActivities") final TaskHandlerAction inDeleteActivitiesAction,
            final ActionController inServiceActionController,
            final OpenSocialPrincipalPopulator inOpenSocialPrincipalPopulator,
            @Named("postPersonActivityServiceActionTaskHandler") final TaskHandlerServiceAction inPostActivityAction,
            @Named("jpaGadgetDefinitionMapper") final GadgetDefinitionMapper inGadgetDefinitionMapper,
            final GadgetMetaDataFetcher inGadgetMetaDataFetcher) {
        getUserActivitiesAction = inGetUserActivitiesAction;
        deleteUserActivities = inDeleteActivitiesAction;
        serviceActionController = inServiceActionController;
        openSocialPrincipalPopulator = inOpenSocialPrincipalPopulator;
        postActivityAction = inPostActivityAction;
        gadgetDefinitionMapper = inGadgetDefinitionMapper;
        gadgetMetaDataFetcher = inGadgetMetaDataFetcher;
    }

    /**
     * Create Activity Implementation for Shindig.
     *
     * @param userId
     *            - id of the user to create the activity for.
     * @param groupId
     *            - id of the group that the user belongs to.
     * @param appId
     *            - id of the application creating the activity.
     * @param fields
     *            - //TODO not sure about this one yet.
     * @param activity
     *            - the activity to be added.
     * @param token
     *            - the security token for the request.
     *
     * @return void
     */
    public Future<Void> createActivity(final UserId userId, final GroupId groupId, final String appId,
            final Set<String> fields, final Activity activity, final SecurityToken token) {
        log.debug("Entering createActivity data with userId " + userId.getUserId(token) + ", appId " + appId + ", "
                + fields.size() + ", AcivityId " + activity.getId() + ", token appId " + token.getAppId());
        try {
            Principal currentUserPrincipal = openSocialPrincipalPopulator.getPrincipal(userId.getUserId(token));

            // Create the actor.
            StreamEntityDTO actorEntity = new StreamEntityDTO();
            actorEntity.setUniqueIdentifier(currentUserPrincipal.getOpenSocialId());
            actorEntity.setType(EntityType.PERSON);

            // Create the destination stream.
            StreamEntityDTO destStream = new StreamEntityDTO();
            destStream.setUniqueIdentifier(currentUserPrincipal.getAccountId());
            destStream.setType(EntityType.PERSON);

            // Create the activitydto object.
            ActivityDTO currentActivity = new ActivityDTO();
            currentActivity.setActor(actorEntity);
            currentActivity
                    .setBaseObjectProperties(new HashMap<String, String>(convertActivityFromOSToEureka(activity)));
            Long appIdNumeric = Long.valueOf(appId);
            currentActivity.setAppId(appIdNumeric);
            currentActivity.setAppType(EntityType.APPLICATION);
            currentActivity.setAppName(lookupGadgetTitle(appIdNumeric));

            // Sets default activity type
            if (!currentActivity.getBaseObjectProperties().containsKey("baseObjectType")) {
                currentActivity.setBaseObjectType(BaseObjectType.NOTE);
            } else {
                String objectType = currentActivity.getBaseObjectProperties().get("baseObjectType");
                currentActivity.setBaseObjectType(BaseObjectType.valueOf(objectType));

                if (currentActivity.getBaseObjectProperties().containsKey("source")) {
                    currentActivity.setAppSource(currentActivity.getBaseObjectProperties().get("source"));
                }
            }

            currentActivity.setVerb(ActivityVerb.POST);
            currentActivity.setDestinationStream(destStream);

            PostActivityRequest params = new PostActivityRequest(currentActivity);
            ServiceActionContext currentContext = new ServiceActionContext(params, currentUserPrincipal);
            // Make the call to the action to perform the create.
            serviceActionController.execute(currentContext, postActivityAction);
        } catch (Exception e) {
            log.error("Error occurred creating Activity ", e);
            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
        }

        return ImmediateFuture.newInstance(null);
    }

    /**
     * Retrieves the gadget's title given it's ID.
     *
     * @param appId
     *            Gadget ID.
     * @return Title.
     * @throws Exception
     *             On error.
     */
    private String lookupGadgetTitle(final Long appId) throws Exception {
        // TODO: This is the brute-force approach. It gets the gadget definition from the database, then uses the gadget
        // metadata fetcher which does a whole bunch of stuff that we don't need (e.g. user prefs, etc.) -- all just so
        // we can get the title. Note that we should not use the title from the gadget definition even though it is
        // there - it is deprecated.
        GadgetDefinition gadgetDef = gadgetDefinitionMapper.findById(appId);
        List<GadgetMetaDataDTO> gadgetsMetadata = gadgetMetaDataFetcher.getGadgetsMetaData(
                Collections.singletonMap(gadgetDef.getUrl(), (GeneralGadgetDefinition) gadgetDef));
        return gadgetsMetadata.get(0).getTitle();
    }

    /**
     * Delete activities implementation for Shindig.
     *
     * @param userId
     *            - id of the user to delete the activities for.
     * @param groupId
     *            - id of the group the user is in.
     * @param appId
     *            - id of the application deleting the activities.
     * @param activityIds
     *            - set of ids to be deleted.
     * @param token
     *            - the security token for the request.
     *
     * @return void
     */
    public Future<Void> deleteActivities(final UserId userId, final GroupId groupId, final String appId,
            final Set<String> activityIds, final SecurityToken token) {
        log.debug("Entering deleteActivities data with userId" + userId.getUserId(token) + ", appId " + appId + ", "
                + activityIds.size() + ", token appId " + token.getAppId());

        Principal currentUserPrincipal = openSocialPrincipalPopulator.getPrincipal(userId.getUserId(token));

        try {
            // convert set of string to list of longs to call action with.
            ArrayList<Long> params = new ArrayList<Long>(activityIds.size());
            for (String id : activityIds) {
                params.add(Long.parseLong(id));
            }

            // create the action context.
            ServiceActionContext currentContext = new ServiceActionContext(params, currentUserPrincipal);

            // execute the action.
            serviceActionController.execute(currentContext, deleteUserActivities);
        } catch (Exception e) {
            log.error("Error occurred deleting OpenSocial Application Data " + e.toString());

            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.toString());
        }
        return ImmediateFuture.newInstance(null);
    }

    /**
     * Shindig implementation for retrieving activities from a set of users.
     *
     * @param userIds
     *            - set of userIds to retrieve activities for.
     * @param groupId
     *            - //TODO not sure about this one yet.
     * @param appId
     *            - id of the application requesting the activities.
     * @param fields
     *            - set of fields to retrieve.
     * @param options
     *            - collection of options for retrieving activities.
     * @param token
     *            - the security token for the request.
     *
     * @return collection of activities.
     */
    @SuppressWarnings("unchecked")
    public Future<RestfulCollection<Activity>> getActivities(final Set<UserId> userIds, final GroupId groupId,
            final String appId, final Set<String> fields, final CollectionOptions options,
            final SecurityToken token) {
        log.trace("Entering getActivities");

        List<Activity> osActivities = new ArrayList<Activity>();

        try {
            Set<String> userIdList = new HashSet<String>();
            for (UserId currentUserId : userIds) {
                if (!currentUserId.getUserId(token).equals("null")) {
                    userIdList.add(currentUserId.getUserId(token));
                }
            }

            log.debug("Sending getActivities userIdList to action: " + userIdList.toString());

            GetUserActivitiesRequest currentRequest = new GetUserActivitiesRequest(new ArrayList<Long>(),
                    userIdList);
            ServiceActionContext currentContext = new ServiceActionContext(currentRequest,
                    openSocialPrincipalPopulator.getPrincipal(token.getViewerId()));

            LinkedList<ActivityDTO> activities = (LinkedList<ActivityDTO>) serviceActionController
                    .execute(currentContext, getUserActivitiesAction);

            log.debug("Retrieved " + activities.size() + " activities from action");

            for (ActivityDTO currentActivity : activities) {
                osActivities.add(convertActivityFromEurekaActivityDTOToOS(currentActivity));
            }
        } catch (Exception ex) {
            log.error("Error occurred retrieving activities ", ex);
            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
        }

        return ImmediateFuture.newInstance(new RestfulCollection<Activity>(osActivities));
    }

    /**
     * Shindig implementation for retrieving activities from a single user.
     *
     * @param userId
     *            - id of the user to retrieve the activities for.
     * @param groupId
     *            - id of the group that the user is a member of.
     * @param appId
     *            - id of the application requesting the activities.
     * @param fields
     *            - set of fields to retrieve for the activity.
     * @param options
     *            - collection of options for retrieving the activities.
     * @param activityIds
     *            - set of ids of the activities to retrieve.
     * @param token
     *            - the security token for the request.
     *
     * @return collection of activities.
     */
    @SuppressWarnings("unchecked")
    public Future<RestfulCollection<Activity>> getActivities(final UserId userId, final GroupId groupId,
            final String appId, final Set<String> fields, final CollectionOptions options,
            final Set<String> activityIds, final SecurityToken token) {
        log.trace("Entering getActivities");
        List<Activity> osActivities = new ArrayList<Activity>();
        try {
            log.debug("Sending getActivities activityIdList to action: " + activityIds.toString());

            LinkedList<Long> activityIdsForRequest = new LinkedList<Long>();
            for (String currentActivityId : activityIds) {
                activityIdsForRequest.add(new Long(currentActivityId));
            }

            Set<String> openSocialIdsForRequest = new HashSet<String>();
            openSocialIdsForRequest.add(userId.getUserId(token));

            GetUserActivitiesRequest currentRequest = new GetUserActivitiesRequest(activityIdsForRequest,
                    openSocialIdsForRequest);
            ServiceActionContext currentContext = new ServiceActionContext(currentRequest,
                    openSocialPrincipalPopulator.getPrincipal(userId.getUserId(token)));

            LinkedList<ActivityDTO> activities = (LinkedList<ActivityDTO>) serviceActionController
                    .execute(currentContext, getUserActivitiesAction);

            log.debug("Retrieved " + activities.size() + " activities from action");

            for (ActivityDTO currentActivity : activities) {
                osActivities.add(convertActivityFromEurekaActivityDTOToOS(currentActivity));
            }
        } catch (Exception ex) {
            log.error("Error occurred retrieving activities ", ex);
            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
        }

        return ImmediateFuture.newInstance(new RestfulCollection<Activity>(osActivities));
    }

    /**
     * Shindig implementation for retrieving a single activity.
     *
     * @param userId
     *            - id of the user to retrieve the activity for.
     * @param groupId
     *            - id of the group that the user belongs to.
     * @param appId
     *            - id of the application requesting the activity.
     * @param fields
     *            - //TODO not sure about this yet.
     * @param activityId
     *            - id of the activity to retrieve.
     * @param token
     *            - the security token for the request.
     *
     * @return single Activity
     */
    public Future<Activity> getActivity(final UserId userId, final GroupId groupId, final String appId,
            final Set<String> fields, final String activityId, final SecurityToken token) {
        // put the activity id in a list and call the getActivities method
        Set<String> activityIds = new HashSet<String>();
        activityIds.add(activityId);

        Future<RestfulCollection<Activity>> activities = getActivities(userId, groupId, appId, fields, null,
                activityIds, token);

        // pull the returned activitity out of the list and return it to the client
        Future<Activity> outActivity = null;
        try {
            outActivity = ImmediateFuture.newInstance(activities.get().getEntry().get(0));
        } catch (Exception e) {
            log.error(e);
        }

        return outActivity;
    }

    /**
     * Helper method that converts a passed in eurekastreams ActivityDTO object into a Shindig Activity object.
     *
     * @param inEurekaActivityDTO
     *            - eurekastreams ActivityDTO to be converted.
     * @return converted OpenSocial Activity object.
     */
    private Activity convertActivityFromEurekaActivityDTOToOS(final ActivityDTO inEurekaActivityDTO) {
        Activity osActivity = new ActivityImpl();

        // TODO: this code needs to be refactor when new message object rearch is done.
        // Populate the OpenSocial Activity properties.
        // osActivity.setAppId(inEurekaActivity.getAppId());
        // osActivity.setBody(inEurekaActivity.getBody());
        // osActivity.setBodyId(inEurekaActivity.getBodyId());
        osActivity.setExternalId(String.valueOf(inEurekaActivityDTO.getId()));
        // osActivity.setId(String.valueOf(inEurekaActivityDTO.getEntityId()));
        osActivity.setUpdated(inEurekaActivityDTO.getPostedTime());
        // osActivity.setPriority(inEurekaActivity.getPriority());
        // osActivity.setStreamFaviconUrl(inEurekaActivity.getStreamFaviconUrl());
        // osActivity.setStreamSourceUrl(inEurekaActivity.getStreamSourceUrl());
        osActivity.setStreamTitle(inEurekaActivityDTO.getDestinationStream().getDisplayName());
        // osActivity.setStreamUrl(inEurekaActivity.getStreamUrl());
        // osActivity.setTemplateParams(inEurekaActivity.getTemplateParams());
        osActivity.setTitle(inEurekaActivityDTO.getBaseObjectProperties().get("Content"));
        // osActivity.setTitleId(inEurekaActivity.getTitleId());
        // osActivity.setUrl(inEurekaActivity.getUrl());
        osActivity.setUserId(inEurekaActivityDTO.getActor().getUniqueIdentifier());

        return osActivity;
    }

    /**
     * Helper method that converts a passed in eurekastreams Activity object into a Shindig Activity object.
     *
     * @param inOSActivity
     *            - eurekastreams Activity to be converted.
     * @return converted Activity object.
     */
    private HashMap<String, String> convertActivityFromOSToEureka(final Activity inOSActivity) {
        HashMap<String, String> outMap = new HashMap<String, String>();

        outMap.put("appId", inOSActivity.getAppId());
        if (inOSActivity.getBody() == null) {
            outMap.put("body", "body");
        } else {
            outMap.put("body", inOSActivity.getBody());
        }
        outMap.put("bodyId", inOSActivity.getBodyId());
        outMap.put("id", inOSActivity.getExternalId());
        outMap.put("openSocialId", inOSActivity.getId());
        if (inOSActivity.getUpdated() != null) {
            outMap.put("updated", inOSActivity.getUpdated().toString());
        }
        if (inOSActivity.getPostedTime() != null) {
            outMap.put("postedTime", inOSActivity.getPostedTime().toString());
        }

        if (inOSActivity.getPriority() == null) {
            outMap.put("priority", Float.valueOf(0).toString());
        } else {
            outMap.put("priority", inOSActivity.getPriority().toString());
        }
        outMap.put("streamFaviconUrl", inOSActivity.getStreamFaviconUrl());
        outMap.put("streamSourceUrl", inOSActivity.getStreamSourceUrl());
        outMap.put("streamTitle", inOSActivity.getStreamTitle());
        outMap.put("streamUrl", inOSActivity.getStreamUrl());

        if (inOSActivity.getTemplateParams() != null) {
            for (Entry<String, String> currentEntry : inOSActivity.getTemplateParams().entrySet()) {
                outMap.put(currentEntry.getKey(), currentEntry.getValue());
            }
        }

        if (inOSActivity.getTitle() != null && inOSActivity.getTitle().length() > 0) {
            outMap.put("content", inOSActivity.getTitle());
        } else {
            outMap.put("content", inOSActivity.getTitleId());
        }
        outMap.put("url", inOSActivity.getUrl());
        outMap.put("userId", inOSActivity.getUserId());

        return outMap;
    }
}