Develop a Facebook-App with Spring-Social – Part II: How Spring Social Works

In this series of Mini-How-Tow’s I will describe how to develop a facebook app with the help of Spring-Social.

In the last part of this series, we took control of the autoconfiguration, that Spring Boot had put in place for us.
But there is still a lot of magic in our little example, that was borrowed from the offical “Getting Started”-guides or at least, it looks so.

First Time In The Electric-Wonder-Land

When I first run the example, I wondered like “Wow, how does this little piece of code figures out which data to fetch? How is Spring Social told, which data to fetch? That must be stored in the session, or so! But where is that configured?” and so on and so on.

When we connect to Facebook, Facebook tells Spring Social, which user is logged in and if this user authorizes the requested access.
We get an access-token from facebook, that can be used to retrieve user-related data from the Graph-API.
Our application has to manage this data.

Spring Social assists us on that task.
But in the end, we have to make the decisions, how to deal with it.

Whom Are You Intrested In?

Spring Social provides the concept of a ConnectionRepository, which is used to persist the connections of specific user.
Spring Social also provides the concept of a UsersConnectionRepository, which stores, whether a user is connected to a specific social service or not.
As described in the official documentation, Spring Social uses the UsersConnectionRepository to create a request-scoped ConnectionRepository bean (the bean named facebook in our little example), that is used by us to access the Graph-API.

But to be able to do so, it must know which user we are interested in!

Hence, Spring Social requires us to configure a UserIdSource.
Every time, when it prepares a request for us, Spring Social will ask this source, which user we are interested in.

Attentive readers might have noticed, that we have configured such a source, when we were explicitly rebuilding the automatic default-configuration of Spring Boot:

public class AnonymousUserIdSource implements UserIdSource
{
  @Override
  public String getUserId()
  {
    return "anonymous";
  }
}

No One Special…

But what is that?!?
All the time we are only interested in one and the same user, whose connections should be stored under the key anonymous?

And what will happen, if a second user connects to our app?

Let’s Test That!

To see what happens, if more than one user connects to your app, you have to create a test user.
This is very simple.
Just go to the dashboard of your app, select the menu-item “Roles” and click on the tab “Test Users”.
Select a test user (or create a new one) and click on the “Edit”-button.
There you can select “Log in as this test user”.

If you first connect to the app as yourself and afterwards as test user, you will see, that your data is presented to the test user.

That is, because we are telling Spring Social that every user is called anonymous.
Hence, every user is the same for Spring Social!
When the test user fetches the page, after you have connected to Facebook as yourself, Spring-Social is thinking, that the same user is returning and serves your data.

Coming next…

In the next part of this series, we will try to teach Spring Social to distinguish between several users.

Funded by the Europian Union

This article was published in the course of a
resarch-project,
that is funded by the European Union and the federal state Northrhine-Wetphalia.


Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung
EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung

Develop a Facebook-App with Spring-Social – Part I: Behind the Scenes

In this series of Mini-How-Tow’s I will describe how to develop a facebook app with the help of Spring-Social.

In the last and first part of this series, I prepared you for our little course.

In this part we will take a look behind the scenes and learn more about the autoconfiguration performed by Spring-Boot, which made our first small example so automagically.

The Source is With You

You can find the source-code on http://juplo.de/git/examples/facebook-app/
and browse it via gitweb.
Check out part-01 to get the source for this part of the series.

Our Silent Servant Behind the Scenes: Spring-Boot

While looking at our simple example from the last part of this series, you may have wondered, how all this is wired up.
You can log in a user from facebook, access his public profile and all this without one line of configuration.


This is achieved via Spring-Boot autoconfiguration.

What comes in very handy in the beginning, sometimes get’s in your way, when your project grows.
This may happen, because these parts of the code are not under your control and you do not know what the autoconfiguration is doing on your behalf.
Because of that, in this part of our series, we will rebuild the most relevant parts of the configuration by hand.
As you will see later, this is not only an exercise, but will lead us to the first improvement of our little example.

What Is Going On Here?

In our case, two Spring-Boot configuration-classes are defining the configuration.
These two classes are SocialWebAutoConfiguration and FacebookAutoConfiguration.
Both classes are located in the package spring-boot-autoconfigure.

The first one configures the ConnectController, sets up an instance of InMemoryUsersConnectionRepository as persitent store for user/connection-mappings and sets up a UserIdService on our behalf, that always returns the user-id anonymous.

The second one adds an instance of FacebookConnectionFactory to the list of available connection-factories, if the required properties (spring.social.facebook.appId and spring.social.facebook.appSecret) are available.
It also configures, that a request-scoped bean of the type Connection<Facebook> is created for each request, that has a known user, who is connected to the Graph-API.

Rebuild This Configuration By Hand

The following class rebuilds the same configuration explicitly:

@Configuration
@EnableSocial
public class SocialConfig extends SocialConfigurerAdapter
{
  /**
   * Add a {@link FacebookConnectionFactory} to the configuration.
   * The factory is configured through the keys <code>facebook.app.id</code>
   * and <,code>facebook.app.secret</code>.
   *
   * @param config
   * @param env 
   */
  @Override
  public void addConnectionFactories(
      ConnectionFactoryConfigurer config,
      Environment env
      )
  {
    config.addConnectionFactory(
        new FacebookConnectionFactory(
            env.getProperty("facebook.app.id"),
            env.getProperty("facebook.app.secret")
            )
        );
  }

  /**
   * Configure an instance of {@link InMemoryUsersConnection} as persistent
   * store of user/connection-mappings.
   *
   * At the moment, no special configuration is needed.
   *
   * @param connectionFactoryLocator
   *     The {@link ConnectionFactoryLocator} will be injected by Spring.
   * @return
   *     The configured {@link UsersConnectionRepository}.
   */
  @Override
  public UsersConnectionRepository getUsersConnectionRepository(
      ConnectionFactoryLocator connectionFactoryLocator
      )
  {
    InMemoryUsersConnectionRepository repository =
        new InMemoryUsersConnectionRepository(connectionFactoryLocator);
    return repository;
  }

  /**
   * Configure a {@link UserIdSource}, that is equivalent to the one, that is
   * created by Spring-Boot.
   *
   * @return
   *     An instance of {@link AnonymousUserIdSource}.
   *
   * @see {@link AnonymousUserIdSource}
   */
  @Override
  public UserIdSource getUserIdSource()
  {
    return new AnonymousUserIdSource();
  }


  /**
   * Configuration of the controller, that handles the authorization against
   * the Facebook-API, to connect a user to Facebook.
   *
   * At the moment, no special configuration is needed.
   *
   * @param factoryLocator
   *     The {@link ConnectionFactoryLocator} will be injected by Spring.
   * @param repository
   *     The {@link ConnectionRepository} will be injected by Spring.
   * @return
   *     The configured controller.
   */
  @Bean
  public ConnectController connectController(
      ConnectionFactoryLocator factoryLocator,
      ConnectionRepository repository
      )
  {
    ConnectController controller =
        new ConnectController(factoryLocator, repository);
    return controller;
  }

  /**
   * Configure a scoped bean named <code>facebook</code>, that enables
   * access to the Graph-API in the name of the current user.
   *
   * @param repository
   *     The {@link ConnectionRepository} will be injected by Spring.
   * @return
   *     A {@Connection}, that represents the authorization of the
   *     current user against the Graph-API, or null, if the
   *     current user is not connected to the API.
   */
  @Bean
  @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
  public Facebook facebook(ConnectionRepository repository)
  {
    Connection connection =
        repository.findPrimaryConnection(Facebook.class);
    return connection != null ? connection.getApi() : null;
  }
}

If you run this refined version of our app, you will see, that it behaves in exact the same way, as the initial version.

Coming next

You may ask, why we should rebuild the configuration by hand, if it does the same thing.
This is, because the example, so far, would not work as a real app.
The first step, to refine it, is to take control of the configuration.

In the next part of this series, I will show you, why this is necessary.
But, first, we have to take a short look into Spring Social.

Funded by the Europian Union

This article was published in the course of a
resarch-project,
that is funded by the European Union and the federal state Northrhine-Wetphalia.


Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung
EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung

Develop a Facebook-App with Spring-Social – Part 0: Prepare

In this series of Mini-How-Tow’s I will describe how to develop a facebook app with the help of Spring-Social.

The goal of this series is not, to show how simple it is to set up your first social app with Spring Social.
Even though the usual getting-started guides, like the one this series is based on, are really simple at first glance, they IMHO tend to be confusing, if you try to move on.
I started with the example from the original Getting-Started guide “Accessing Facebook Data” and planed to extend it to handle a sign-in via the canvas-page of facebook, like in the Spring Social Canvas-Example.
But I was not able to achieve that simple refinement and ran into multiple obstacles.

Because of that, I wanted to show the refinement-process from a simple example up to a full-fledged facebook-app.
My goal is, that you should be able to reuse the final result of the last part of this series as blueprint and starting-point for your own project.
At the same time, you should be able to jump back to earlier posts and read all about the design-decisions, that lead up to that result.

This part of my series will handle the preconditions of our first real development-steps.

The Source is With You

The source-code can be found on http://juplo.de/git/examples/facebook-app/
and browsed via gitweb.
For every part I will add a corresponding tag, that denotes the differences between the earlier and the later development steps.

Keep it Simple

We will start with the most simple app possible, that just displays the public profile data of the logged in user.
This app is based on the code of the original Getting-Started guide “Accessing Facebook Data” from Spring-Social.

But it is simplified and cleand a little.
And I fixed some small bugs: the original code from
https://github.com/spring-guides/gs-accessing-facebook.git
produces a
NullPointerException and won’t work with the current version 2.0.3.RELEASE of spring-social-facebook, because it uses the depreceated scope read_stream.

The code for this.logging.level.de.juplo.yourshouter= part is tagged with part-00.
Appart from the HTML-templates, the attic for spring-boot and the build-definitions in the pom.xml it mainly consists of one file:

@Controller
@RequestMapping("/")
public class HomeController
{
  private final static Logger LOG = LoggerFactory.getLogger(HomeController.class);


  private final Facebook facebook;


  @Inject.logging.level.de.juplo.yourshouter=
  public HomeController(Facebook facebook)
  {
    this.facebook = facebook;
  }


  @RequestMapping(method = RequestMethod.GET)
  public String helloFacebook(Model model)
  {
    boolean authorized = true;
    try
    {
      authorized = facebook.isAuthorized();
    }
    catch (NullPointerException e)
    {
      LOG.debug("NPE while acessing Facebook: {}", e);
      authorized = false;
    }
    if (!authorized)
    {
      LOG.info("no authorized user, redirecting to /connect/facebook");
      return "redirect:/connect/facebook";
    }

    User user = facebook.userOperations().getUserProfile();
    LOG.info("authorized user {}, id: {}", user.getName(), user.getId());
    model.addAttribute("user", user);
    return "home";
  }
}

I removed every unnecessary bit, to clear the view for the relevant part.
You can add your styling and stuff by yourself later…

Automagic

The magic of Spring-Social is hidden in the autoconfiguration of Spring-Boot, which will be revealed and refined/replaced in the next parts of this series.

Run it!

You can clone the repository, checkout the right version and run it with the following commands:

git clone http://juplo.de/git/examples/facebook-app/
cd facebook-app
checkout part-00
mvn spring-boot:run \
    -Dfacebook.app.id=YOUR_ID \
    -Dfacebook.app.secret=YOUR_SECRET

Of course, you have to replace YOUR_ID and YOUR_SECRET with the ID and secret of your Facebook-App.
What you have to do to register as a facebook-developer and start your first facebook-app is described in this “Getting Started”-guide from Spring-Social.

In addition to what is described there, you have to configure the URL of your website.
To do so, you have to navigate to the Settings-panel of your newly registered facebook-app.
Click on Add Platform and choose Website.
Then, enter http://localhost:8080/ as the URL of your website.

After maven has downloaded all dependencies and started the Spring-Boot application in the embedded tomcat, you can point your browser to http://localhost:8080, connect, go back to the welcome-page and view the public data of the account you connected with your app.

Coming next…

Now, you are prepared to learn Spring-Social and develop your first app step by step.
I will guide you through the process in the upcoming parts of this series.

In the next part of this series I will explain, why this example from the “Getting Started”-guide would not work as a real application and what has to be done, to fix that.

Funded by the Europian Union

This article was published in the course of a
resarch-project,
that is funded by the European Union and the federal state Northrhine-Wetphalia.


Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung
EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung