Package org.eurekastreams.server.service.opensocial.spi

Source Code of org.eurekastreams.server.service.opensocial.spi.PersonServiceImpl

/*
* Copyright (c) 2009-2011 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.Arrays;
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.GroupId.Type;
import org.apache.shindig.social.opensocial.spi.PersonService;
import org.apache.shindig.social.opensocial.spi.UserId;
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.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.persistence.mappers.DomainMapper;
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;

    /**
     * DAO for retrieving {@link Principal} objects given OpenSocial IDs.
     */
    private final DomainMapper<String, Principal> principalDao;

    /**
     * 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 inOpenSocialPrincipalDao
     *            DAO for retrieving {@link Principal} objects given OpenSocial IDs.
     * @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,
            @Named("openSocialPrincipalDaoTransWrapped") final DomainMapper<String, Principal> inOpenSocialPrincipalDao,
            final ActionController inServiceActionController,
            @Named("eureka.container.baseurl") final String inContainerBaseUrl,
            @Named("eureka.user-account-tld") final String inAccountTopLevelDomain)
    {
        getPeopleAction = inGetPeopleAction;
        getFollowingAction = inGetFollowingAction;
        containerBaseUrl = inContainerBaseUrl;
        principalDao = inOpenSocialPrincipalDao;
        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
     *
     */
    @Override
    @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 ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server Error");
                }

                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());

                // This is iterating through the list to avoid failing entire call for users that are not
                // in the Eureka db.
                people = new LinkedList<PersonModelView>();
                for (String userId : userIdList)
                {
                    GetPeopleByOpenSocialIdsRequest currentRequest = new GetPeopleByOpenSocialIdsRequest(
                            Arrays.asList(userId), groupId.getType().toString().toLowerCase());

                    ServiceActionContext currentContext = new ServiceActionContext(currentRequest, getPrincipal(token));
                    PersonModelView result = null;
                    try
                    {
                        result = ((LinkedList<PersonModelView>) serviceActionController.execute(currentContext,
                                getPeopleAction)).getFirst();
                    }
                    catch (Exception e)
                    {
                        log.warn("Requested user: " + userId + " was requested, but not found in eureka system");
                    }

                    if (result == null)
                    {
                        result = createNonUserPersonModelView(userId);
                    }

                    people.add(result);
                }
            }

            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, "Server Error");
        }

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

    /**
     * Create bogus PersonModelView for users not in system.
     *
     * @param userId
     *            requested userId.
     * @return Bogus PersonModelView for users not in system.
     */
    private PersonModelView createNonUserPersonModelView(final String userId)
    {
        PersonModelView nonUser = new PersonModelView();
        // Populate the OpenSocial person properties.
        nonUser.setDisplayName(userId);
        nonUser.setOpenSocialId(userId);
        nonUser.setDescription("Non Eureka user");
        nonUser.setAccountId(userId);
        nonUser.setEmail("nonEurekaUser@lmco.com");
        nonUser.setAvatarId(null);

        return nonUser;
    }

    /**
     * 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
     */
    @Override
    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_INTERNAL_SERVER_ERROR, "Server Error");
        }

        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(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_INTERNAL_SERVER_ERROR, "Server Error");
        }
        catch (Exception ex)
        {
            log.error("Error occurred retrieving person.", ex);

            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Server Error");
        }

        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 = principalDao.execute(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.getAvatarId()));

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

        return osPerson;
    }
}
TOP

Related Classes of org.eurekastreams.server.service.opensocial.spi.PersonServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.