Struts2 - Actions with multiple methods?

I am new to this site and this is my first question.

I need to make a website, I use java and Struts2, but I'm new to Struts2.

On my site, I have to make requests on Facebook and receive authentication using OAuth.

I perform the whole process (authenticate and request secure resources) in the method of executing the action page, this process is very complex and has many redirects between Facebook and my network.

The other day I read this: "Do not create actions with several methods:" execute ", and the operation you want to perform (for example," createUser ") should be sufficient" (from http://freeopenidea.blogspot.com.es/ 2010/04 / struts2-best-practices.html ).

Most of the code can be called from another part of my site at another moment, because I do this process when I connect for the first time, but I could do it (or something like that) to update the contact list.

1 - Should I create a separate class (and not an action) for the methods that I need and call them from the "execute" method?

2 - Should I store the code on the action page, but in methods other than "execute"? And call this page every time I need to perform some tasks.

I don’t know where to put the code (and I know I have to store accessToken. I just paste the code to show complexity, but I don’t look at the fix).

public String execute() throws Exception{ if (code!=null){ Verifier verifier = new Verifier(code); //get the accessToken to do requests Token accessToken = service.getAccessToken(EMPTY_TOKEN, verifier); OAuthRequest requestList = new OAuthRequest(Verb.GET, PROTECTED_RESOURCE_URL); service.signRequest(accessToken, requestList); Response responseList = requestList.send(); if (responseList.getCode() == 200){ //I get the Friends List JsonParse parser = new JsonParse(); JSONObject json = (JSONObject) JSONSerializer.toJSON(responseList.getBody()); JSONArray datos = json.getJSONArray("data"); for (Object o : datos) {//for every friend of the list I do this JSONObject elem = (JSONObject) o; String id = elem.getString("id"); OAuthRequest requestFriend = new OAuthRequest(Verb.GET,"https://graph.facebook.com/"+id); service.signRequest(accessToken, requestFriend); Response responseFriend = requestFriend.send(); if (responseFriend.getCode() == 200){ JsonParse parserAux = new JsonParse(); PerfilContacto pcBean = parserAux.parseFacebookElement(responseFriend.getBody()); pcDAO.insertarContacto(pcBean); } } } return SUCCESS; } else return ERROR; } 
+4
source share
1 answer

IMO that too much code in the action method. Actions should handle the layer between the website and the business layer, and a little more. This level of communication, especially with hard-coded class instances, makes it very difficult to test action logic in isolation.

Move essentially all of this code to the service. The action applies only to interaction with the service. The frame checks for the presence of code . The service is tested outside of Struts 2. The action is tested using the mock service.

Completely untested, but I suspect my code will be much closer to the one below. He trades one type of difficulty for another, but brings many advantages. Each method is closely focused and easy to read. Service calls are isolated, which allows us to test various ways of service failures. This is a detailed view of the behavior and functionality of the system.

Act

 public String execute() throws Exception { fbService.updateFriends(code); return SUCCESS; } 

FB Service

 public void updateFriends(String code) { Token accessToken = getAccessToken(code); Response response = getFriends(accessToken); if (response.getCode() == 200) { processFriends(accessToken, response); } } private void processFriends(Token accessToken, Response response) { JSONObject json = (JSONObject) JSONSerializer.toJSON(response.getBody()); JSONArray datos = json.getJSONArray("data"); for (Object o : datos) { JSONObject friend = (JSONObject) o; processFriend(friend); } } private void processFriend(Token accessToken, JSONObject friend) { Response response = getFriendGraph(accessToken, friend.getString("id")); if (response.getCode() == 200){ PerfilContacto pcBean = new JsonParse().parseFacebookElement(response.getBody()); pcDAO.insertarContacto(pcBean); } } //~ Service interaction private Response getFriends(Token accessToken) { return sendSignedGetRequest(PROTECTED_RESOURCE_URL, accessToken); } private Response getFriendGraph(Token accessToken, String id) { return sendSignedGetRequest("https://graph.facebook.com/" + id, accessToken); } private Token getAccessToken(String code) { return service.getAccessToken(EMPTY_TOKEN, new Verifier(code)); } private Response sendSignedGetRequest(String url, Token accessToken) { OAuthRequest request = new OAuthRequest(Verb.GET, url); service.signRequest(accessToken, request); return request.send(); } 

If we look at metrics, we get the following.

Original:

 Average Function NCSS: 24.00 Average Function CCN: 6.00 Program NCSS: 25.00 

Redesigned:

 Average Function NCSS: 3.63 Average Function CCN: 1.38 Program NCSS: 31.00 

Ultimately, this means:

  • The number of significant LOCs did not increase.
  • Each function is <4 lines long (easy to read).
  • Each cyclic complexity of a function is <2 (easy to verify and justify).
  • A program reads more than what it does, making it easier to understand.

The trade-off is that we have more methods (which should not be a huge problem, given any reasonable IDE or text editor), which is complexity. But:

  • We can stop reading the depth of our choice.
  • We can test with much more detail.
  • We can identify success / failure modes that we may have missed.
  • We can swap and / or expand functionality more easily.
+3
source

Source: https://habr.com/ru/post/1435109/


All Articles