org.alfresco.mobile.android.api.session.impl.CloudSessionImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.alfresco.mobile.android.api.session.impl.CloudSessionImpl.java

Source

/*******************************************************************************
 * Copyright (C) 2005-2013 Alfresco Software Limited.
 * 
 * This file is part of the Alfresco Mobile SDK.
 * 
 * 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.alfresco.mobile.android.api.session.impl;

import static org.alfresco.mobile.android.api.constants.OAuthConstant.PUBLIC_API_HOSTNAME;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.alfresco.mobile.android.api.constants.CloudConstant;
import org.alfresco.mobile.android.api.exceptions.AlfrescoSessionException;
import org.alfresco.mobile.android.api.exceptions.ErrorCodeRegistry;
import org.alfresco.mobile.android.api.exceptions.impl.ExceptionHelper;
import org.alfresco.mobile.android.api.model.PagingResult;
import org.alfresco.mobile.android.api.model.RepositoryInfo;
import org.alfresco.mobile.android.api.model.impl.FolderImpl;
import org.alfresco.mobile.android.api.model.impl.PagingResultImpl;
import org.alfresco.mobile.android.api.model.impl.cloud.CloudRepositoryInfoImpl;
import org.alfresco.mobile.android.api.network.NetworkHttpInvoker;
import org.alfresco.mobile.android.api.services.impl.cloud.CloudServiceRegistry;
import org.alfresco.mobile.android.api.session.AlfrescoSession;
import org.alfresco.mobile.android.api.session.CloudNetwork;
import org.alfresco.mobile.android.api.session.CloudSession;
import org.alfresco.mobile.android.api.session.authentication.AuthenticationProvider;
import org.alfresco.mobile.android.api.session.authentication.OAuthAuthenticationProvider;
import org.alfresco.mobile.android.api.session.authentication.OAuthData;
import org.alfresco.mobile.android.api.session.authentication.impl.OAuth2AuthenticationProviderImpl;
import org.alfresco.mobile.android.api.session.authentication.impl.PassthruAuthenticationProviderImpl;
import org.alfresco.mobile.android.api.utils.CloudUrlRegistry;
import org.alfresco.mobile.android.api.utils.PublicAPIResponse;
import org.alfresco.mobile.android.api.utils.messages.Messagesl18n;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.bindings.spi.http.Response;
import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
import org.apache.chemistry.opencmis.commons.impl.UrlBuilder;
import org.apache.http.HttpStatus;

import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

/**
 * RepositorySession represents a connection to a cloud repository as a specific
 * user.
 * 
 * @author Jean Marie Pascal
 */
public class CloudSessionImpl extends CloudSession {
    /** Internal : Activate Basic Authentication. */
    private static final String CLOUD_BASIC_AUTH = "org.alfresco.mobile.binding.internal.cloud.basic";

    private static final String TAG = "CloudSessionImpl";

    /** Network associated to this Cloud session. */
    private CloudNetwork currentNetwork;

    public CloudSessionImpl() {

    }

    /**
     * Create a cloud Session based on OAuth information and Parameters.
     * 
     * @param oauthData : Authentification context data
     * @param parameters : Session context data
     */
    public CloudSessionImpl(OAuthData oauthData, Map<String, Serializable> parameters) {
        Map<String, Serializable> tmpProperties = new HashMap<String, Serializable>();
        if (parameters != null) {
            tmpProperties.putAll(parameters);
        }

        // Add user identifier if it's not previously added
        // By default for cloud don't use a specific username but -me-
        if (oauthData != null && !tmpProperties.containsKey(USER)) {
            tmpProperties.put(USER, USER_ME);
        }

        initSettings(PUBLIC_API_HOSTNAME, tmpProperties);

        // Normal case : With OAuth data.
        if (oauthData != null) {
            // Creation of the OAuthenticationProvider associated with
            // OAuthInformation.
            authenticate(new OAuth2AuthenticationProviderImpl(oauthData));
        }
        // Normal case : With Basic Authentication data.
        else if (hasParameter(CLOUD_BASIC_AUTH)) {
            authenticate(null);
        }
        // Exception case : No authentication mechanism available
        else {
            throw new IllegalArgumentException(String
                    .format(Messagesl18n.getString("ErrorCodeRegistry.GENERAL_INVALID_ARG_NULL"), "OAuthData"));
        }
    }

    /** Start the authentication proces. */
    private void authenticate(AuthenticationProvider authProvider) {
        try {
            // If no authenticationProvider start creation of
            // BasicAuthenticationProvider by default or the one provided by
            // session parameter.
            if (authProvider == null) {
                authenticator = createAuthenticationProvider((String) userParameters.get(AUTHENTICATOR_CLASSNAME));
            } else {
                authenticator = authProvider;
            }

            // Retrieve & select the Home Network or session parameters network.
            PagingResult<CloudNetwork> networks = getPagingNetworks();
            if (networks == null || networks.getTotalItems() == 0) {
                throw new AlfrescoSessionException(ErrorCodeRegistry.SESSION_NO_NETWORK_FOUND,
                        Messagesl18n.getString("SESSION_NO_NETWORK_FOUND"));
            }

            String networkIdentifier = null;
            if (hasParameter(CLOUD_NETWORK_ID)) {
                networkIdentifier = (String) getParameter(CLOUD_NETWORK_ID);
            }

            List<CloudNetwork> listNetworks = networks.getList();

            // Support GMail case where a user has a disabled homeNetwork
            // cf. MOBSDK-506.
            // In this case it's the latest enabled network which is going to be
            // available as default Network for the session.
            for (CloudNetwork cloudNetwork : listNetworks) {
                if (cloudNetwork.isHomeNetwork() && ((CloudNetworkImpl) cloudNetwork).isEnabled()
                        && networkIdentifier == null) {
                    currentNetwork = cloudNetwork;
                    break;
                } else if (networkIdentifier != null && networkIdentifier.equals(cloudNetwork.getIdentifier())) {
                    currentNetwork = cloudNetwork;
                    break;
                } else if (!cloudNetwork.isHomeNetwork() && ((CloudNetworkImpl) cloudNetwork).isEnabled()) {
                    currentNetwork = cloudNetwork;
                }
            }

            if (currentNetwork == null) {
                throw new AlfrescoSessionException(ErrorCodeRegistry.SESSION_NO_NETWORK_FOUND,
                        Messagesl18n.getString("SESSION_NO_NETWORK_FOUND"));
            }

            // Create OpenCMIS Session Parameters
            addParameter(CLOUD_NETWORK_ID, currentNetwork.getIdentifier());
            Map<String, String> param = retrieveSessionParameters();

            // Create CMIS Session with selected network + parameters
            cmisSession = createSession(SessionFactoryImpl.newInstance(), authenticator, param);

            // Init Services + Object
            try {
                if (cmisSession.getRootFolder() != null) {
                    rootNode = new FolderImpl(cmisSession.getRootFolder());
                }
            } catch (Exception e) {
                Log.e(TAG, "Unable to retrieve rootNode folder");
                Log.e(TAG, Log.getStackTraceString(e));
            }

            repositoryInfo = new CloudRepositoryInfoImpl(cmisSession.getRepositoryInfo());

            create();
        } catch (Exception e) {
            throw new AlfrescoSessionException(ErrorCodeRegistry.SESSION_GENERIC, e);
        }
    }

    private void create() {
        // Extension Point to implement and manage services
        if (hasParameter(AlfrescoSession.CLOUD_SERVICES_CLASSNAME)) {
            services = createServiceRegistry((String) getParameter(AlfrescoSession.CLOUD_SERVICES_CLASSNAME));
        } else {
            services = new CloudServiceRegistry(this);
        }

        // Retrieve AuthenticationProvider
        passThruAuthenticator = cmisSession.getBinding().getAuthenticationProvider();
        authenticator = ((PassthruAuthenticationProviderImpl) passThruAuthenticator)
                .getAlfrescoAuthenticationProvider();
    }

    // //////////////////////////////////////////////////////////////
    // Authentication Provider
    // /////////////////////////////////////////////////////////////
    /**
     * Create the Alfresco AuthenticationProvider. Used by the default
     * "CMIS enable" PassThruAuthenticationProvider.
     * 
     * @param className
     * @return
     */
    private AuthenticationProvider createAuthenticationProvider(String className) {
        AuthenticationProvider s = null;
        try {
            Class<?> c = Class.forName(className);
            Constructor<?> t = c.getDeclaredConstructor(Map.class);
            s = (AuthenticationProvider) t.newInstance(userParameters);
        } catch (Exception e) {
            throw new AlfrescoSessionException(ErrorCodeRegistry.SESSION_AUTHENTICATOR, e);
        }
        return s;
    }

    // //////////////////////////////////////////////////////////////
    // Networks
    // /////////////////////////////////////////////////////////////
    @SuppressWarnings("unchecked")
    private PagingResult<CloudNetwork> getPagingNetworks() {
        UrlBuilder builder = new UrlBuilder(CloudUrlRegistry.getUserNetworks(baseUrl));

        Response resp = NetworkHttpInvoker.invokeGET(builder, authenticator.getHTTPHeaders());

        // check response code
        if (resp.getResponseCode() != HttpStatus.SC_OK) {
            ExceptionHelper.convertStatusCode(null, resp, ErrorCodeRegistry.SESSION_GENERIC);
        }

        PublicAPIResponse response = new PublicAPIResponse(resp);

        List<CloudNetwork> result = new ArrayList<CloudNetwork>();
        Map<String, Object> data = null;
        for (Object entry : response.getEntries()) {
            data = (Map<String, Object>) ((Map<String, Object>) entry).get(CloudConstant.ENTRY_VALUE);
            result.add(CloudNetworkImpl.parsePublicAPIJson(data));
        }

        return new PagingResultImpl<CloudNetwork>(result, response.getHasMoreItems(), response.getSize());
    }

    @Override
    public List<CloudNetwork> getNetworks() {
        return getPagingNetworks().getList();
    }

    @Override
    public CloudNetwork getNetwork() {
        return currentNetwork;
    }

    protected void switchNetwork(CloudNetwork network) {
        currentNetwork = network;
    }

    @Override
    public void setOAuthData(OAuthData data) {
        if (authenticator != null && authenticator instanceof OAuthAuthenticationProvider
                && data instanceof OAuthData) {
            ((OAuthAuthenticationProvider) authenticator).setOAuthData((OAuthData) data);
        }
    }

    @Override
    public OAuthData getOAuthData() {
        if (authenticator != null && authenticator instanceof OAuthAuthenticationProvider) {
            return ((OAuthAuthenticationProvider) authenticator).getOAuthData();
        } else {
            return null;
        }
    }

    // ////////////////////////////////////////////////////
    // Save State - serialization / deserialization
    // ////////////////////////////////////////////////////
    @Override
    public int describeContents() {
        return 0;
    }

    public static final Parcelable.Creator<CloudSessionImpl> CREATOR = new Parcelable.Creator<CloudSessionImpl>() {
        public CloudSessionImpl createFromParcel(Parcel in) {
            return new CloudSessionImpl(in);
        }

        public CloudSessionImpl[] newArray(int size) {
            return new CloudSessionImpl[size];
        }
    };

    @Override
    public void writeToParcel(Parcel dest, int arg1) {
        dest.writeString(baseUrl);
        dest.writeString(userIdentifier);
        dest.writeString(password);
        dest.writeSerializable(currentNetwork);
        dest.writeParcelable(rootNode, PARCELABLE_WRITE_RETURN_VALUE);
        dest.writeSerializable(repositoryInfo);
        dest.writeSerializable(cmisSession);
        Bundle b = new Bundle();
        b.putSerializable("userParameters", (Serializable) userParameters);
        dest.writeBundle(b);
    }

    @SuppressWarnings("unchecked")
    public CloudSessionImpl(Parcel o) {
        this.baseUrl = o.readString();
        this.userIdentifier = o.readString();
        this.password = o.readString();
        this.currentNetwork = (CloudNetwork) o.readSerializable();
        this.rootNode = o.readParcelable(FolderImpl.class.getClassLoader());
        this.repositoryInfo = (RepositoryInfo) o.readSerializable();
        this.cmisSession = (Session) o.readSerializable();
        Bundle b = o.readBundle();
        this.userParameters = (Map<String, Serializable>) b.getSerializable("userParameters");
        create();
    }
}