com.jiwhiz.domain.account.impl.ConnectionRepositoryImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.jiwhiz.domain.account.impl.ConnectionRepositoryImpl.java

Source

/* 
 * Copyright 2013-2014 JIWHIZ Consulting Inc.
 *
 * 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 com.jiwhiz.domain.account.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.Map.Entry;

import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionData;
import org.springframework.social.connect.ConnectionFactory;
import org.springframework.social.connect.ConnectionKey;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.DuplicateConnectionException;
import org.springframework.social.connect.NoSuchConnectionException;
import org.springframework.social.connect.NotConnectedException;
import org.springframework.social.security.SocialAuthenticationServiceLocator;
import org.springframework.social.security.provider.SocialAuthenticationService;
import org.springframework.social.security.provider.SocialAuthenticationService.ConnectionCardinality;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import com.jiwhiz.domain.account.UserSocialConnection;
import com.jiwhiz.domain.account.UserSocialConnectionRepository;

/**
 * Implementation for Spring Social {@link ConnectionRepository}. Store {@link UserSocialConnection} to Database.
 * 
 * 
 * @author Yuan Ji
 *
 */
public class ConnectionRepositoryImpl implements ConnectionRepository {
    private final String userId;

    private final UserSocialConnectionRepository userSocialConnectionRepository;

    private final SocialAuthenticationServiceLocator socialAuthenticationServiceLocator;

    private final TextEncryptor textEncryptor;

    public ConnectionRepositoryImpl(String userId, UserSocialConnectionRepository userSocialConnectionRepository,
            SocialAuthenticationServiceLocator socialAuthenticationServiceLocator, TextEncryptor textEncryptor) {
        this.userId = userId;
        this.userSocialConnectionRepository = userSocialConnectionRepository;
        this.socialAuthenticationServiceLocator = socialAuthenticationServiceLocator;
        this.textEncryptor = textEncryptor;
    }

    public MultiValueMap<String, Connection<?>> findAllConnections() {
        List<UserSocialConnection> userSocialConnectionList = userSocialConnectionRepository.findByUserId(userId);

        MultiValueMap<String, Connection<?>> connections = new LinkedMultiValueMap<String, Connection<?>>();
        Set<String> registeredProviderIds = socialAuthenticationServiceLocator.registeredProviderIds();
        for (String registeredProviderId : registeredProviderIds) {
            connections.put(registeredProviderId, Collections.<Connection<?>>emptyList());
        }
        for (UserSocialConnection userSocialConnection : userSocialConnectionList) {
            String providerId = userSocialConnection.getProviderId();
            if (connections.get(providerId).size() == 0) {
                connections.put(providerId, new LinkedList<Connection<?>>());
            }
            connections.add(providerId, buildConnection(userSocialConnection));
        }
        return connections;
    }

    public List<Connection<?>> findConnections(String providerId) {
        List<Connection<?>> resultList = new LinkedList<Connection<?>>();
        List<UserSocialConnection> userSocialConnectionList = userSocialConnectionRepository
                .findByUserIdAndProviderId(userId, providerId);
        for (UserSocialConnection userSocialConnection : userSocialConnectionList) {
            resultList.add(buildConnection(userSocialConnection));
        }
        return resultList;
    }

    @SuppressWarnings("unchecked")
    public <A> List<Connection<A>> findConnections(Class<A> apiType) {
        List<?> connections = findConnections(getProviderId(apiType));
        return (List<Connection<A>>) connections;
    }

    public MultiValueMap<String, Connection<?>> findConnectionsToUsers(
            MultiValueMap<String, String> providerUsers) {
        if (providerUsers == null || providerUsers.isEmpty()) {
            throw new IllegalArgumentException("Unable to execute find: no providerUsers provided");
        }

        MultiValueMap<String, Connection<?>> connectionsForUsers = new LinkedMultiValueMap<String, Connection<?>>();

        for (Iterator<Entry<String, List<String>>> it = providerUsers.entrySet().iterator(); it.hasNext();) {
            Entry<String, List<String>> entry = it.next();
            String providerId = entry.getKey();
            List<String> providerUserIds = entry.getValue();
            List<UserSocialConnection> userSocialConnections = userSocialConnectionRepository
                    .findByProviderIdAndProviderUserIdIn(providerId, providerUserIds);
            List<Connection<?>> connections = new ArrayList<Connection<?>>(providerUserIds.size());
            for (int i = 0; i < providerUserIds.size(); i++) {
                connections.add(null);
            }
            connectionsForUsers.put(providerId, connections);

            for (UserSocialConnection userSocialConnection : userSocialConnections) {
                String providerUserId = userSocialConnection.getProviderUserId();
                int connectionIndex = providerUserIds.indexOf(providerUserId);
                connections.set(connectionIndex, buildConnection(userSocialConnection));
            }

        }
        return connectionsForUsers;
    }

    public Connection<?> getConnection(ConnectionKey connectionKey) {
        UserSocialConnection userSocialConnection = this.userSocialConnectionRepository
                .findByUserIdAndProviderIdAndProviderUserId(userId, connectionKey.getProviderId(),
                        connectionKey.getProviderUserId());
        if (userSocialConnection != null) {
            return buildConnection(userSocialConnection);
        }
        throw new NoSuchConnectionException(connectionKey);
    }

    @SuppressWarnings("unchecked")
    public <A> Connection<A> getConnection(Class<A> apiType, String providerUserId) {
        String providerId = getProviderId(apiType);
        return (Connection<A>) getConnection(new ConnectionKey(providerId, providerUserId));
    }

    @SuppressWarnings("unchecked")
    public <A> Connection<A> getPrimaryConnection(Class<A> apiType) {
        String providerId = getProviderId(apiType);
        Connection<A> connection = (Connection<A>) findPrimaryConnection(providerId);
        if (connection == null) {
            throw new NotConnectedException(providerId);
        }
        return connection;
    }

    @SuppressWarnings("unchecked")
    public <A> Connection<A> findPrimaryConnection(Class<A> apiType) {
        String providerId = getProviderId(apiType);
        return (Connection<A>) findPrimaryConnection(providerId);
    }

    public void addConnection(Connection<?> connection) {
        //check cardinality
        SocialAuthenticationService<?> socialAuthenticationService = socialAuthenticationServiceLocator
                .getAuthenticationService(connection.getKey().getProviderId());
        if (socialAuthenticationService.getConnectionCardinality() == ConnectionCardinality.ONE_TO_ONE
                || socialAuthenticationService.getConnectionCardinality() == ConnectionCardinality.ONE_TO_MANY) {
            List<UserSocialConnection> storedConnections = userSocialConnectionRepository
                    .findByProviderIdAndProviderUserId(connection.getKey().getProviderId(),
                            connection.getKey().getProviderUserId());
            if (storedConnections.size() > 0) {
                //not allow one providerId/providerUserId connect to multiple userId
                throw new DuplicateConnectionException(connection.getKey());
            }
        }

        UserSocialConnection userSocialConnection = userSocialConnectionRepository
                .findByUserIdAndProviderIdAndProviderUserId(userId, connection.getKey().getProviderId(),
                        connection.getKey().getProviderUserId());
        if (userSocialConnection == null) {
            ConnectionData data = connection.createData();
            userSocialConnection = new UserSocialConnection(userId, data.getProviderId(), data.getProviderUserId(),
                    0, data.getDisplayName(), data.getProfileUrl(), data.getImageUrl(),
                    encrypt(data.getAccessToken()), encrypt(data.getSecret()), encrypt(data.getRefreshToken()),
                    data.getExpireTime());
            userSocialConnection.setId(UUID.randomUUID().toString());
            userSocialConnectionRepository.save(userSocialConnection);
        } else {
            throw new DuplicateConnectionException(connection.getKey());
        }
    }

    public void updateConnection(Connection<?> connection) {
        ConnectionData data = connection.createData();
        UserSocialConnection userSocialConnection = this.userSocialConnectionRepository
                .findByUserIdAndProviderIdAndProviderUserId(userId, connection.getKey().getProviderId(),
                        connection.getKey().getProviderUserId());
        if (userSocialConnection != null) {
            userSocialConnection.setDisplayName(data.getDisplayName());
            userSocialConnection.setProfileUrl(data.getProfileUrl());
            userSocialConnection.setImageUrl(data.getImageUrl());
            userSocialConnection.setAccessToken(encrypt(data.getAccessToken()));
            userSocialConnection.setSecret(encrypt(data.getSecret()));
            userSocialConnection.setRefreshToken(encrypt(data.getRefreshToken()));
            userSocialConnection.setExpireTime(data.getExpireTime());
            userSocialConnectionRepository.save(userSocialConnection);
        }
    }

    public void removeConnections(String providerId) {
        List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository
                .findByUserIdAndProviderId(userId, providerId);
        for (UserSocialConnection userSocialConnection : userSocialConnectionList) {
            userSocialConnectionRepository.delete(userSocialConnection);
        }
    }

    public void removeConnection(ConnectionKey connectionKey) {
        UserSocialConnection userSocialConnection = this.userSocialConnectionRepository
                .findByUserIdAndProviderIdAndProviderUserId(userId, connectionKey.getProviderId(),
                        connectionKey.getProviderUserId());
        userSocialConnectionRepository.delete(userSocialConnection);
    }

    // internal helpers

    private Connection<?> buildConnection(UserSocialConnection userSocialConnection) {
        ConnectionData connectionData = new ConnectionData(userSocialConnection.getProviderId(),
                userSocialConnection.getProviderUserId(), userSocialConnection.getDisplayName(),
                userSocialConnection.getProfileUrl(), userSocialConnection.getImageUrl(),
                decrypt(userSocialConnection.getAccessToken()), decrypt(userSocialConnection.getSecret()),
                decrypt(userSocialConnection.getRefreshToken()), userSocialConnection.getExpireTime());
        ConnectionFactory<?> connectionFactory = socialAuthenticationServiceLocator
                .getConnectionFactory(connectionData.getProviderId());
        return connectionFactory.createConnection(connectionData);
    }

    private Connection<?> findPrimaryConnection(String providerId) {
        List<UserSocialConnection> userSocialConnectionList = this.userSocialConnectionRepository
                .findByUserIdAndProviderId(userId, providerId);

        return buildConnection(userSocialConnectionList.get(0));
    }

    private <A> String getProviderId(Class<A> apiType) {
        return socialAuthenticationServiceLocator.getConnectionFactory(apiType).getProviderId();
    }

    private String encrypt(String text) {
        return text != null ? textEncryptor.encrypt(text) : text;
    }

    private String decrypt(String encryptedText) {
        return encryptedText != null ? textEncryptor.decrypt(encryptedText) : encryptedText;
    }
}