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

Java tutorial

Introduction

Here is the source code for org.eurekastreams.server.service.opensocial.spi.PersonServiceImpl.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.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.AccountImpl;
import org.apache.shindig.social.core.model.ListFieldImpl;
import org.apache.shindig.social.core.model.NameImpl;
import org.apache.shindig.social.core.model.PersonImpl;
import org.apache.shindig.social.opensocial.model.Account;
import org.apache.shindig.social.opensocial.model.ListField;
import org.apache.shindig.social.opensocial.model.Person;
import org.apache.shindig.social.opensocial.spi.CollectionOptions;
import org.apache.shindig.social.opensocial.spi.GroupId;
import org.apache.shindig.social.opensocial.spi.PersonService;
import org.apache.shindig.social.opensocial.spi.UserId;
import org.apache.shindig.social.opensocial.spi.GroupId.Type;
import org.eurekastreams.commons.actions.context.Principal;
import org.eurekastreams.commons.actions.context.PrincipalActionContext;
import org.eurekastreams.commons.actions.context.service.ServiceActionContext;
import org.eurekastreams.commons.actions.service.ServiceAction;
import org.eurekastreams.commons.server.service.ActionController;
import org.eurekastreams.server.action.principal.PrincipalPopulatorTransWrapper;
import org.eurekastreams.server.action.request.opensocial.GetPeopleByOpenSocialIdsRequest;
import org.eurekastreams.server.action.request.profile.GetFollowersFollowingRequest;
import org.eurekastreams.server.domain.AvatarUrlGenerator;
import org.eurekastreams.server.domain.EntityType;
import org.eurekastreams.server.domain.PagedSet;
import org.eurekastreams.server.search.modelview.PersonModelView;

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

/**
 * This class is the Eureka Streams implementation of the Shindig interface for retrieving OpenSocial information about
 * People.
 * 
 */
public class PersonServiceImpl implements PersonService {
    /**
     * Logger.
     */
    private final Log log = LogFactory.getLog(PersonServiceImpl.class);

    /**
     * Service Action Controller.
     */
    private final ActionController serviceActionController;

    /**
     * Principal populator.
     */
    private final PrincipalPopulatorTransWrapper principalPopulator;

    /**
     * Instance of the GetPersonAction that is used to process Person requests.
     */
    private final ServiceAction getPeopleAction;

    /**
     * Instance of the GetFollowingAction that is used to process Friends requests.
     */
    private final ServiceAction getFollowingAction;

    /**
     * Container base url to create profile url from.
     */
    private final String containerBaseUrl;

    /** Top-level domain used for users' accounts. */
    private final String accountTopLevelDomain;

    /**
     * Basic constructor for the PersonService implementation.
     * 
     * @param inGetPeopleAction
     *            - this is the GetPeopleAction that is injected into this class with Spring. This action is used to
     *            retrieve multiple person objects in a single request.
     * @param inGetFollowingAction
     *            - this is the GetFollowingAction that is injected into this class with Spring. This action is used to
     *            retrieve the friends of the requestor.
     * @param inOpenSocialPrincipalPopulator
     *            {@link PrincipalPopulatorTransWrapper}.
     * @param inServiceActionController
     *            {@link ActionController}.
     * @param inContainerBaseUrl
     *            - string that contains the base url for the container to be used when generating links for an
     *            opensocial person.
     * @param inAccountTopLevelDomain
     *            Top-level domain used for users' accounts.
     */
    @Inject
    public PersonServiceImpl(@Named("getPeopleByOpenSocialIds") final ServiceAction inGetPeopleAction,
            @Named("getFollowing") final ServiceAction inGetFollowingAction,
            final PrincipalPopulatorTransWrapper inOpenSocialPrincipalPopulator,
            final ActionController inServiceActionController,
            @Named("eureka.container.baseurl") final String inContainerBaseUrl,
            @Named("eureka.user-account-tld") final String inAccountTopLevelDomain) {
        getPeopleAction = inGetPeopleAction;
        getFollowingAction = inGetFollowingAction;
        containerBaseUrl = inContainerBaseUrl;
        principalPopulator = inOpenSocialPrincipalPopulator;
        serviceActionController = inServiceActionController;
        accountTopLevelDomain = inAccountTopLevelDomain;
    }

    /**
     * This is the implementation method to retrieve a number of people generally associated with a group or by a set of
     * userids.
     * 
     * @param userIds
     *            - set of userids to retrieve.
     * @param groupId
     *            - group id to retrieve.
     * @param collectionOptions
     *            - collection options.
     * @param fields
     *            - fields to retrieve with these users.
     * @param token
     *            - security token for this request.
     * 
     * @return instance of person
     * 
     */
    @SuppressWarnings("unchecked")
    public Future<RestfulCollection<Person>> getPeople(final Set<UserId> userIds, final GroupId groupId,
            final CollectionOptions collectionOptions, final Set<String> fields, final SecurityToken token) {
        log.trace("Entering getPeople");
        List<Person> osPeople = new ArrayList<Person>();
        LinkedList<PersonModelView> people = null;
        try {
            if (groupId.getType().equals(Type.friends)) {
                Principal currentPrincipal = getPrincipal(token);
                if (currentPrincipal == null) {
                    throw new IllegalArgumentException("Invalid requestor");
                }

                GetFollowersFollowingRequest currentRequest = new GetFollowersFollowingRequest(EntityType.PERSON,
                        currentPrincipal.getAccountId(), 0, Integer.MAX_VALUE);

                ServiceActionContext currentContext = new ServiceActionContext(currentRequest, currentPrincipal);

                PagedSet<PersonModelView> peopleResults = (PagedSet<PersonModelView>) serviceActionController
                        .execute(currentContext, getFollowingAction);

                people = new LinkedList<PersonModelView>(peopleResults.getPagedSet());
            } else {
                LinkedList<String> userIdList = new LinkedList<String>();
                for (UserId currentUserId : userIds) {
                    if (!currentUserId.getUserId(token).equals("null")) {
                        userIdList.add(currentUserId.getUserId(token));
                    }
                }

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

                GetPeopleByOpenSocialIdsRequest currentRequest = new GetPeopleByOpenSocialIdsRequest(userIdList,
                        groupId.getType().toString().toLowerCase());

                ServiceActionContext currentContext = new ServiceActionContext(currentRequest, getPrincipal(token));

                people = (LinkedList<PersonModelView>) serviceActionController.execute(currentContext,
                        getPeopleAction);
            }

            if (log.isDebugEnabled()) {
                log.debug("Retrieved " + people.size() + " people from action");
            }

            for (PersonModelView currentPerson : people) {
                osPeople.add(convertToOSPerson(currentPerson));
            }
        } catch (Exception ex) {
            log.error("Error occurred retrieving people ", ex);
            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
        }

        return ImmediateFuture.newInstance(new RestfulCollection<Person>(osPeople));
    }

    /**
     * This is the implementation of the getPerson method specified by Shindig. This is how Shindig's OpenSocial api
     * will interact with our database.
     * 
     * @param id
     *            - userid making the request.
     * @param fields
     *            - set of fields to be retrieved with this request.
     * @param token
     *            - token that goes with this request.
     * 
     * @return instance of Person object
     */
    public Future<Person> getPerson(final UserId id, final Set<String> fields, final SecurityToken token) {
        log.trace("Entering getPerson");
        Person osPerson = new PersonImpl();

        String openSocialId = null;

        // Retrieve the user id.
        if (id.getUserId(token) != null) {
            openSocialId = id.getUserId(token);
        } else
        // userId is null and so is the type cannot proceed.
        {
            log.debug("Id of the person requested was null");
            throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST, "No id supplied");
        }

        try {
            log.debug("User id requested is: " + openSocialId);

            LinkedList<String> userIdList = new LinkedList<String>();
            userIdList.add(openSocialId);

            // Build up request to retrieve a single person.
            GetPeopleByOpenSocialIdsRequest currentRequest = new GetPeopleByOpenSocialIdsRequest(userIdList,
                    Type.all.toString());

            // Create the actionContext
            PrincipalActionContext ac = new ServiceActionContext(currentRequest, getPrincipal(token));

            // execute action.
            LinkedList<PersonModelView> people = (LinkedList<PersonModelView>) serviceActionController
                    .execute((ServiceActionContext) ac, getPeopleAction);

            if (people.size() > 0) {
                osPerson = convertToOSPerson(people.getFirst());
            }
        } catch (NumberFormatException e) {
            log.error("number format exception " + e.getMessage());

            throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST, "Id supplied is bad.");
        } catch (Exception e) {
            log.error("Error occurred retrieving person " + e.getMessage());

            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
        }

        return ImmediateFuture.newInstance(osPerson);
    }

    /**
     * Get Principal object for current user. Currently this method allows an unauthenticated request to retrieve
     * opensocial information about a user. The authentication is handled within shindig, not here. There may be a need
     * for an authorization strategy to not allow this access even if you have anonymous auth configured in shindig.
     * TODO: Put in authorization strategy for the underlying action.
     * 
     * @param inSecurityToken
     *            - current security token for the request.
     * @return Principal object based on the security token or null if an anonymous request.
     */
    private Principal getPrincipal(final SecurityToken inSecurityToken) {
        Principal currentUserPrincipal = null;
        if (inSecurityToken.getViewerId() != null) {
            currentUserPrincipal = principalPopulator.getPrincipal(inSecurityToken.getViewerId(), "");
        }
        return currentUserPrincipal;
    }

    /**
     * Helper method that converts a passed in eurekastreams Person object into a Shindig Person object.
     * 
     * @param inPerson
     *            - eurekastreams person to be converted.
     * @return converted person object.
     */
    private Person convertToOSPerson(final PersonModelView inPerson) {
        Person osPerson = new PersonImpl();
        // Populate the OpenSocial person properties.
        osPerson.setName(new NameImpl(inPerson.getDisplayName()));
        osPerson.setDisplayName(inPerson.getDisplayName());
        osPerson.setId(inPerson.getOpenSocialId());
        osPerson.setAboutMe(inPerson.getDescription());
        osPerson.setProfileUrl(containerBaseUrl + "/#people/" + inPerson.getAccountId());

        List<ListField> emailList = new ArrayList<ListField>();
        emailList.add(new ListFieldImpl("primary", inPerson.getEmail()));
        osPerson.setEmails(emailList);

        AvatarUrlGenerator generator = new AvatarUrlGenerator(EntityType.PERSON);
        osPerson.setThumbnailUrl(
                containerBaseUrl + generator.getNormalAvatarUrl(inPerson.getId(), inPerson.getAvatarId()));

        osPerson.setAccounts(Collections
                .singletonList((Account) new AccountImpl(accountTopLevelDomain, null, inPerson.getAccountId())));

        return osPerson;
    }
}