protected void updateCustomFields(
      User user, Userinfo userinfo, String accessToken, String refreshToken)
      throws PortalException, SystemException {

    ExpandoValueLocalServiceUtil.addValue(
        user.getCompanyId(),
        User.class.getName(),
        ExpandoTableConstants.DEFAULT_TABLE_NAME,
        GOOGLE_ACCESS_TOKEN,
        user.getUserId(),
        accessToken);

    ExpandoValueLocalServiceUtil.addValue(
        user.getCompanyId(),
        User.class.getName(),
        ExpandoTableConstants.DEFAULT_TABLE_NAME,
        GOOGLE_REFRESH_TOKEN,
        user.getUserId(),
        refreshToken);

    ExpandoValueLocalServiceUtil.addValue(
        user.getCompanyId(),
        User.class.getName(),
        ExpandoTableConstants.DEFAULT_TABLE_NAME,
        GOOGLE_USER_ID,
        user.getUserId(),
        userinfo.getId());
  }
  /**
   * Retrieve credentials using the provided authorization code.
   *
   * <p>This function exchanges the authorization code for an access token and queries the UserInfo
   * API to retrieve the user's e-mail address. If a refresh token has been retrieved along with an
   * access token, it is stored in the application database using the user's e-mail address as key.
   * If no refresh token has been retrieved, the function checks in the application database for one
   * and returns it if found or throws a NoRefreshTokenException with the authorization URL to
   * redirect the user to.
   *
   * @return Credential containing an access and refresh token.
   * @throws NoRefreshTokenException No refresh token could be retrieved from the available sources.
   * @throws IOException
   */
  public Credential getActiveCredential() throws NoRefreshTokenException, IOException {
    String userId = (String) request.getSession().getAttribute(USER_ID_KEY);
    Credential credential = null;
    try {
      // Only bother looking for a Credential if the user has an existing
      // session with their email address stored.
      if (userId != null) {
        credential = getStoredCredential(userId);
      }

      // No Credential was stored for the current user or no refresh token is
      // available.
      // If an authorizationCode is present, upgrade it into an
      // access token and hopefully a refresh token.
      if ((credential == null || credential.getRefreshToken() == null)
          && request.getParameter("code") != null) {
        credential = exchangeCode(request.getParameter("code"));
        if (credential != null) {
          Userinfo userInfo = getUserInfo(credential);
          userId = userInfo.getId();
          request.getSession().setAttribute(USER_ID_KEY, userId);
          request.getSession().setAttribute(EMAIL_KEY, userInfo.getEmail());
          // Sometimes we won't get a refresh token after upgrading a code.
          // This won't work for our app, because the user can land directly
          // at our app without first visiting Google Drive. Therefore,
          // only bother to store the Credential if it has a refresh token.
          // If it doesn't, we'll get one below.
          if (credential.getRefreshToken() != null) {
            credentialStore.store(userId, credential);
          }
        }
      }

      if (credential == null || credential.getRefreshToken() == null) {
        // No refresh token has been retrieved.
        // Start a "fresh" OAuth 2.0 flow so that we can get a refresh token.
        String email = (String) request.getSession().getAttribute(EMAIL_KEY);
        String authorizationUrl = getAuthorizationUrl(email);
        throw new NoRefreshTokenException(authorizationUrl);
      }
    } catch (CodeExchangeException e) {
      // The code the user arrived here with was bad.  This pretty much never
      // happens. In a production application, we'd either redirect the user
      // somewhere like a home page, or show them a vague error mentioning
      // that they probably didn't arrive to our app from Google Drive.
      e.printStackTrace();
    } catch (NoUserIdException e) {
      // This is bad because it means the user either denied us access
      // to their email address, or we couldn't fetch it for some reason.
      // This is unrecoverable. In a production application, we'd show the
      // user a message saying that we need access to their email address
      // to work.
      e.printStackTrace();
    }
    return credential;
  }
  protected User setGoogleCredentials(HttpSession session, long companyId, Credential credential)
      throws Exception {

    Userinfo userinfo = getUserInfo(credential);

    if (userinfo == null) {
      return null;
    }

    User user = null;

    String emailAddress = userinfo.getEmail();

    if ((user == null) && Validator.isNotNull(emailAddress)) {
      user = UserLocalServiceUtil.fetchUserByEmailAddress(companyId, emailAddress);

      if ((user != null) && (user.getStatus() != WorkflowConstants.STATUS_INCOMPLETE)) {

        session.setAttribute("GOOGLE_USER_EMAIL_ADDRESS", emailAddress);
      }
    }

    if (user != null) {
      if (user.getStatus() == WorkflowConstants.STATUS_INCOMPLETE) {
        session.setAttribute("GOOGLE_INCOMPLETE_USER_ID", userinfo.getId());

        user.setEmailAddress(userinfo.getEmail());
        user.setFirstName(userinfo.getGivenName());
        user.setLastName(userinfo.getFamilyName());

        return user;
      }

      user = updateUser(user, userinfo);
    } else {
      user = addUser(session, companyId, userinfo);
    }

    if (DeployManagerUtil.isDeployed(_GOOGLE_DRIVE_CONTEXT)) {
      updateCustomFields(user, userinfo, credential.getAccessToken(), credential.getRefreshToken());
    }

    return user;
  }
  protected Userinfo getUserInfo(Credential credentials) throws NoSuchUserIdException {

    Oauth2.Builder builder =
        new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credentials);

    Oauth2 oauth2 = builder.build();

    Userinfo userInfo = null;

    try {
      userInfo = oauth2.userinfo().get().execute();
    } catch (IOException e) {
      System.err.println("An error occurred: " + e);
    }

    if ((userInfo != null) && (userInfo.getId() != null)) {
      return userInfo;
    } else {
      throw new NoSuchUserIdException();
    }
  }