Developer
Documentation
Resources
Get Support
Sign in
Developer
Get Support
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in
Developer
Sign in
DOCUMENTATION
Cloud
Data Center
Resources
Sign in

Fisheye and Crucible Development : Stage 4 Twitter access configuration

Register the app in Twitter

To access the Twitter Platform, you need to obtain a Consumer Key/Secret pair and an Access Token/Secret pair. Every user who wants his commits to be tweeted needs to do this.

Go to https://apps.twitter.com/ and select Create new app. Once done, open the Keys and Access Tokens tab, then click Create my access token.

Debug: check Twitter access

Once you have the 4 authentication strings, you might want to check if they are correct and if they truly let you post to Twitter. You can do so with this debug code:

TwitterStatusUpdater.java

1
2
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.conf.PropertyConfiguration;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Properties;

/**
 * Little app to ensure authorisation works and you can publish tweets to Twitter.
 * First use {@link TwitterTokenGenerator} to obtain access token/secret pair. Then provide this script with the consumer
 * key/secret and access token/secret. Lastly, type in the twitter message you want to post.
 */
public class TwitterStatusUpdater {

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // Consumer key + consumer secret
        print("Enter consumer key:");
        String consumerKey = br.readLine();
        print("Enter consumer secret:");
        String consumerSecret = br.readLine();

        // Access token + access token secret
        print("Enter access token:");
        String token = br.readLine();
        print("Enter access token secret:");
        String tokenSecret = br.readLine();

        TwitterFactory twitterFactory = new TwitterFactory(new PropertyConfiguration(new Properties() {{
            put("oauth.consumerKey", consumerKey);
            put("oauth.consumerSecret", consumerSecret);
            put("oauth.accessToken", token);
            put("oauth.accessTokenSecret", tokenSecret);
        }}));

        Twitter twitter = twitterFactory.getInstance();
        twitter.verifyCredentials();

        print("Enter your Twitter status update:");
        String twitterUpdate = br.readLine();
        twitter.updateStatus(twitterUpdate);
        print("No exceptions, so your update seems successful");
    }

    private static void print(String x) {
        System.out.println(x);
    }
}

Bean of Twitter data

We'd like to store the 4 authentication strings as one object:

TwitterLoginRecord.java

1
2
public class TwitterLoginRecord {

    private final String consumerKey;
    private final String consumerSecret;
    private final String token;
    private final String tokenSecret;

    public TwitterLoginRecord(String consumerKey,
                              String consumerSecret,
                              String token,
                              String tokenSecret) {
        this.consumerKey = consumerKey;
        this.consumerSecret = consumerSecret;
        this.token = token;
        this.tokenSecret = tokenSecret;
    }

    public String getConsumerKey() {
        return consumerKey;
    }

    public String getConsumerSecret() {
        return consumerSecret;
    }

    public String getTokenSecret() {
        return tokenSecret;
    }

    public String getToken() {
        return token;
    }
}

Servlet for Twitter data input

We need to change the "Hello world!" servlet to become a form for typing in the data that will become TwitterLoginRecord. First declare the variable-class mapping on the first line of the template:

twitterSettings.vm

1
2
#* @vtlvariable name="loginRecord" type="com.example.ampstutorial.TwitterAccessTokenRecord" *#

Then change the body to become a form:

twitterSettings.vm

1
2
<body>
<div>
    <form action="./twitter-settings" method="post">
        <table class="dialog-prefs" cellspacing="0">
            <thead>
            <tr>
                <th colspan="2"><h3>Twitter Settings</h3></th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td class="tdLabel"><label for="consumerKey" class="label">Consumer key:</label></td>
                <td><input type="text" name="consumerKey" value="${loginRecord.consumerKey}" id="consumerKey"/></td>
            </tr>
            <tr>
                <td class="tdLabel"><label for="consumerSecret" class="label">Consumer secret:</label></td>
                <td><input type="password" name="consumerSecret" value="${loginRecord.consumerSecret}" id="consumerSecret"/></td>
            </tr>
            <tr>
                <td class="tdLabel"><label for="token" class="label">Token:</label></td>
                <td><input type="text" name="token" value="${loginRecord.token}" id="token"/></td>
            </tr>
            <tr>
                <td class="tdLabel"><label for="tokenSecret" class="label">Token secret:</label></td>
                <td><input type="password" name="tokenSecret" value="${loginRecord.tokenSecret}" id="tokenSecret"/></td>
            </tr>
            <tr>
                <td></td>
                <td class="action"><input type="submit" value="Save"/></td>
            </tr>
            </tbody>
        </table>
    </form>
</div>
</body>

Note that action="./token-servlet" specifies where the form will post the collected data.

Save data from the servlet post

To accept the data posted from the form, override the doPost method:

TwitterSettingsServlet.java

1
2
import static com.google.common.base.Strings.isNullOrEmpty;
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String consumerKey = request.getParameter("consumerKey");
        String consumerSecret = request.getParameter("consumerSecret");
        String token = request.getParameter("token");
        String tokenSecret = request.getParameter("tokenSecret");

        if (       !isNullOrEmpty(consumerKey)
                && !isNullOrEmpty(consumerSecret)
                && !isNullOrEmpty(token)
                && !isNullOrEmpty(tokenSecret)) {
            storeLoginRecord(consumerKey, consumerSecret, token, tokenSecret);
        }
        response.sendRedirect("./twitter-settings");
    }

Note how the parameter names match those in the twitterSettings.vm form.

Store TwitterLoginRecords

For the purposes of this tutorial, the username and password are just stored in a  Map  in a field of the servlet - this is not persistent. To learn how to save configuration data for your plugins see  Storing Plugin Settings for Fisheye .

We'll use TwitterLoginRecordStore interface, so that we can easily switch to a persistent store in the future.

TwitterLoginRecordStore.java

1
2
public interface TwitterLoginRecordStore {

    TwitterLoginRecord get(String userName);
    
    void put(String userName, TwitterLoginRecord record);
}

TwitterLoginRecordStoreImpl.java

1
2
import java.util.HashMap;
import java.util.Map;

public class TwitterLoginRecordStoreImpl implements TwitterLoginRecordStore {

    private final Map<String, TwitterLoginRecord> store = new HashMap<>();

    @Override
    public TwitterLoginRecord get(String userName) {
        return store.get(userName);
    }

    @Override
    public void put(String userName, TwitterLoginRecord record) {
        store.put(userName, record);
    }
}

Add the TwitterLoginRecordStore component

atlassian-plugin.xml

1
2
<component key="twitterLoginRecordStore" class="com.example.ampstutorial.TwitterLoginRecordStoreImpl" public="true">
    <interface>com.example.ampstutorial.TwitterLoginRecordStore</interface>
</component>

Inject and use TwitterLoginRecordStore

TwitterSettingsServlet.java

1
2
private final TwitterLoginRecordStore twitterLoginRecordStore;
private final TemplateRenderer templateRenderer;

public TwitterSettingsServlet(TwitterLoginRecordStore twitterLoginRecordStore, TemplateRenderer templateRenderer) {
    this.twitterLoginRecordStore = twitterLoginRecordStore;
    this.templateRenderer = templateRenderer;
}
 
private void storeLoginRecord(String consumerKey, String consumerSecret, String token, String tokenSecret) {
    twitterLoginRecordStore.put(getCurrentUser(),
    new TwitterLoginRecord(consumerKey, consumerSecret, token, tokenSecret));
}

Get the current user login

We use the user login as the key in the store. To get the current user login, we use EffectiveUserProvider. Add a new dependency:

pom.xml

1
2
<dependency>
    <groupId>com.atlassian.fisheye</groupId>
    <artifactId>fisheye-jar</artifactId>
    <version>3.10.0-SNAPSHOT</version>
    <scope>provided</scope>
</dependency>

Inject the user provider to the servlet and use it:

TwitterSettingsServlet.java

1
2
import com.atlassian.fecru.user.EffectiveUserProvider;

    private final EffectiveUserProvider effectiveUserProvider;

    public TwitterSettingsServlet(EffectiveUserProvider effectiveUserProvider,
                                  TwitterLoginRecordStore twitterLoginRecordStore,
                                  TemplateRenderer templateRenderer) {
        this.effectiveUserProvider = effectiveUserProvider;
        this.twitterLoginRecordStore = twitterLoginRecordStore;
        this.templateRenderer = templateRenderer;
    }
 
    private String getCurrentUser() {
        return effectiveUserProvider.getEffectiveUserLogin().getUserName();
    }

Load TwitterLoginRecord to fill the form

Once saved, we want to show the data in the form. To fill the form template, we need to modify the get method:

TwitterSettingsServlet.java

1
2
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.setAttribute("decorator", "fisheye.userprofile.tab");
    response.setContentType("text/html");

    TwitterLoginRecord loginRecord = twitterLoginRecordStore.get(getCurrentUser());
            
    templateRenderer.render("/templates/twitterSettings.vm",
        loginRecord != null ? ImmutableMap.of("loginRecord", loginRecord) : ImmutableMap.of(),
        response.getWriter());
}

Rate this page: