Tuesday, January 13, 2026

Working with Java plugins (Half 2)


In my earlier publish, I talked about learn how to mix the Java library Twitter4J and Stata’s Java operate Interface utilizing Eclipse to create a helloWorld plugin. Now, I need to speak about learn how to name Twitter4j member features to hook up with Twitter REST API, return Twitter information, and cargo that information into Stata utilizing the Stata SFI.

Including twitter4J embrace information and globl

The present code is


bundle com.stata.kcrow;

import com.stata.sfi.*;

public class StTwitter {
        public static int HelloWorld(String args[]) {
                SFIToolkit.error("Hey World!");
                return(0);
        }
}

To make use of the twitter4J operate calls, I want so as to add the next code to the highest of our StTwitter.java file:


import twitter4j.*;
import twitter4j.conf.ConfigurationBuilder;

Additionally, I want so as to add a world Twitter class to our StTwitter class. My code now reads


bundle com.stata.kcrow;

import com.stata.sfi.*;

import twitter4j.*;
import twitter4j.conf.ConfigurationBuilder;

public class StTwitter {
        static Twitter twitter;

        public static int HelloWorld(String args[]) {
                SFIToolkit.error("Hey World!");
                return(0);
        }
}

Occasion member operate

Most web site APIs use some type of OAuth for authentication with their servers. Twitter makes use of OAuth2. twitter2stata makes use of Twitter’s application-based authentication mannequin, however there are different methods to attach. For this publish, I may also use the application-based authentication mannequin.

The primary operate I want to put in writing is a operate to authenticate to the Twitter web site API. To do that, you want to get your Client Key (API Key), Client Secret (API Secret), Entry Token, and Entry Token Secret strings. In case you don’t bear in mind learn how to get these, see my earlier weblog publish right here.

After you have these tokens, you’ll be able to then write a easy operate to go this data utilizing the category member operate ConfigurationBuilder:


non-public static void getInstance() {
        ConfigurationBuilder    cb;
        TwitterFactory          tf;

        cb = new ConfigurationBuilder();

        cb.setDebugEnabled(true)
                .setOAuthConsumerKey(CONSUMER_KEY)
                .setOAuthConsumerSecret(CONSUMER_SECRET)
                .setOAuthAccessToken(ACCESS_TOKEN)
                .setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET);

        tf = new TwitterFactory(cb.construct());
        twitter = tf.getInstance();
}

This operate creates a ConfigurationBuilder occasion, units the login settings, creates a Twitter manufacturing facility occasion, after which initializes the worldwide Twitter class occasion. My class now reads


bundle com.stata.kcrow;

import com.stata.sfi.*;

import twitter4j.*;
import twitter4j.conf.ConfigurationBuilder;

public class StTwitter {
        static Twitter twitter ;

        non-public static void getInstance() {
                ConfigurationBuilder    cb;
                TwitterFactory          tf;

                cb = new ConfigurationBuilder();

                cb.setDebugEnabled(true)

.setOAuthConsumerKey("xWNlx*N9vESv0ZZBtGdm7fVB")
.setOAuthConsumerSecret("7D25oVzWeDCHrUlQcp9929@GOcnqWCuUKhDel")
.setOAuthAccessToken("74741598400768-3hAYpZbiDvABPizx5lk57B8CTVyfa")
.setOAuthAccessTokenSecret("7HjDf25oVzDWAeDCHrUlQcpfNGOTzcnqWCuUKhDel");

                tf = new TwitterFactory(cb.construct());
                twitter = tf.getInstance();
        }

        public static int HelloWorld(String args[]) {
                SFIToolkit.error("Hey World!");
                return(0);
        }
}

I made this class non-public as a result of this operate doesn’t must be referred to as from Stata.

Search member operate

Now that I’ve written our occasion operate, I can write our search operate. The Twitter4J features I want are

I’ll use Question to set our search setttings, search() to fetch the search outcomes, and getRateLimitStatus() to make sure I don’t go over the Twitter fee limits. Let’s write our operate to fetch search outcomes 100 at a time and hit the fee limits. Final, I’ll use getTweets() to fetch the Standing objects (actually tweet object). I can loop the Standing objects returned by search() utilizing a for and use a do/whereas loop to verify I’ve outcomes. I coded


public static int searchTweets(String[] args) {
        int                     rc, restrict;
        String                  search_query;
        Question                   question;
        QueryResult             end result;

        getInstance();          //Name static member operate above

        search_query = args[0]; // Argument handed from Stata.

        question = new Question(search_query);
        question.setCount(100);
        end result = null;

        do {
                end result = twitter.search(question);
                restrict = end result.getRateLimitStatus().getRemaining();

                for (Standing tweet_object: end result.getTweets()) {
                        //course of information
                }

        } whereas (restrict > 0);

        return(rc);
}

In Java, it is suggested that you just put code that would lead to an error within the Attempt/Catch block. This makes error dealing with simpler. You should utilize the TwitterException class to assist with error dealing with. This class can generate extra particular error messages, however I cannot use it. For this instance, I’ll concern a generic couldn’t search tweets error for any TwitterException.


public static int searchTweets(String[] args) {
        int                     rc, restrict;
        String                  search_query;
        Question                   question;
        QueryResult             end result;

        getInstance();          //Name static member operate above

        search_query = args[0]; // Argument handed from Stata.

        question = new Question(search_query);
        question.setCount(100);
        end result = null;

        attempt {
                do {
                        end result = twitter.search(question);
                        restrict = end result.getRateLimitStatus().getRemaining();

                        for (Standing tweet_object: end result.getTweets()) {
                                //course of information
                        }
                } whereas (restrict > 0);
        }
        catch (TwitterException te) {
                SFIToolkit.errorln("couldn't search tweets");
                rc = 606
        }
        return(rc);
}

To date, I’ve used two Stata SFI member features:

Each of those features show an error within the Stata Outcomes home windows. The one distinction between the 2 is that SFIToolkit.errorln provides a line terminator on the finish of the error. Now, let’s take a look at the Stata SFI Information class used to course of the information returned from Twitter.

Write information into Stata

To course of the information from Twitter, I have to first add each variables and observations to Stata. So as to add observations to Stata, you employ the SFI Information class operate stObsTotal(). There are a number of features so as to add variables, relying on the kind.

I’ll use addVarStr() and addVarDouble() for this instance. The tweet information Twitter returns is organized into two sorts of information: the tweet object and the consumer object. For this instance, we’re going to course of just a few of the metadata from each objects. From the tweet object I’ll course of:

  • textual content
  • retweet_count
  • favorite_count

From the consumer object, I’ll course of:

  • screen_name
  • followers_count
  • friends_count

In our searchTweets operate, I want so as to add the next code to create our variables and add observations to Stata:


public static int searchTweets(String[] args) {
        int                     rc, restrict;
        String                  search_query;
        Question                   question;
        QueryResult             end result;
        lengthy                    obs ;

        getInstance();          //Name static member operate above

        search_query = args[0]; // Argument handed from Stata.

        question = new Question(search_query);
        question.setCount(100);
        end result = null;

        //Create variables
        rc = Information.addVarStr("textual content", 240);
        if (rc!=0) return(rc);
        rc = Information.addVarDouble("retweet_count");
        if (rc!=0) return(rc);
        rc = Information.addVarDouble("favorite_count");
        if (rc!=0) return(rc);
        rc = Information.addVarStr("screen_name", 30);
        if (rc!=0) return(rc);
        rc = Information.addVarDouble("followers_count");
        if (rc!=0) return(rc);
        rc = Information.addVarDouble("friends_count");
        if (rc!=0) return(rc);

        obs = 0;
        attempt {

                do {
                        end result = twitter.search(question);
                        restrict = end result.getRateLimitStatus().getRemaining();

                        for (Standing tweet_object: end result.getTweets()) {
                                //Add observations
                                obs++;
                                rc = Information.setObsTotal(obs);
                                if (rc!=0) return(rc);
                                //course of information
                        }
                } whereas (restrict > 0);
        }
        catch (TwitterException te) {
                SFIToolkit.errorln("couldn't search tweets");
                rc = 606;
        }
        return(rc);
}

In our searchTweets member operate, I want to put in writing a non-public member operate that copies the outcomes returned from Twitter’s objects into Stata’s reminiscence. I added the under name contained in the for loop.


...
        for (Standing tweet_object: end result.getTweets()) {
                //Add observations
                obs++;
                rc = Information.setObsTotal(obs);
                if (rc!=0) return(rc);
                //course of information
                rc = processData(obs, tweet_object,
                        tweet_object.getUser());
                if (rc!=0) return(rc);
        }

...

The operate is


non-public static int processData(lengthy obs, Standing tweet_object, Person user_object){
        int                     rc;

        rc = Information.storeStr(1, obs, tweet_object.getText());
        if(rc) return(rc);
        rc = Information.storeNum(2, obs, tweet_object.getRetweetCount());
        if(rc) return(rc);
        rc = Information.storeNum(3, obs, tweet_object.getFavoriteCount());
        if(rc) return(rc);

        rc = Information.storeStr(4, obs, user_object.getName());
        if(rc) return(rc);
        rc = Information.storeNum(5, obs, user_object.getFollowersCount());
        if(rc) return(rc);
        rc = Information.storeNum(6, obs, user_object.getFriendsCount());
        if(rc) return(rc);

        return(rc);
}

Observe that the primary argument of the the Information.retailer* is simply the variable index order within the present datasets in reminiscence. You’ll be able to take a look at every operate name to get the metadata for the tweet object right here and for the consumer object right here.

Last class

Our last code to the StTwitter class is


bundle com.stata.kcrow;


import com.stata.sfi.*;

import twitter4j.*;
import twitter4j.conf.ConfigurationBuilder;

public class StTwitter {
        static Twitter twitter;

        non-public static void getInstance() {
                ConfigurationBuilder    cb;
                TwitterFactory          tf;

                cb = new ConfigurationBuilder();

                cb.setDebugEnabled(true)

.setOAuthConsumerKey("xWNlx*N9vESv0ZZBtGdm7fVB")
.setOAuthConsumerSecret("7D25oVzWeDCHrUlQcp9929@GOcnqWCuUKhDel")
.setOAuthAccessToken("74741598400768-3hAYpZbiDvABPizx5lk57B8CTVyfa")
.setOAuthAccessTokenSecret("7HjDf25oVzDWAeDCHrUlQcpfNGOTzcnqWCuUKhDel");

                tf = new TwitterFactory(cb.construct());
                twitter = tf.getInstance();
        }
        public static int searchTweets(String[] args) {
                int                     rc, restrict;
                String                  search_query;
                Question                   question;
                QueryResult             end result;
                lengthy                    obs;

                getInstance();          //Name static member operate above

                search_query = args[0]; // Argument handed from Stata.

                question = new Question(search_query);
                question.setCount(100);
                end result = null;
                //Create variables
                rc = Information.addVarStr("textual content", 240);
                if (rc!=0) return(rc);
                rc = Information.addVarDouble("retweet_count");
                if (rc!=0) return(rc);
                rc = Information.addVarDouble("favorite_count");
                if (rc!=0) return(rc);
                rc = Information.addVarStr("screen_name", 30);
                if (rc!=0) return(rc);
                rc = Information.addVarDouble("followers_count");
                if (rc!=0) return(rc);
                rc = Information.addVarDouble("friends_count");
                if (rc!=0) return(rc);

                obs = 0 ;
                attempt {

                        do {
                             end result = twitter.search(question);
                             restrict = end result.getRateLimitStatus().getRemaining();

                           for (Standing tweet_object: end result.getTweets()) {
                                   //Add observations
                                   obs++;
                                   rc = Information.setObsTotal(obs);
                                   if (rc!=0) return(rc);
                                   //course of information
                                   rc = processData(obs, tweet_object,
                                          tweet_object.getUser());
                                   if (rc!=0) return(rc);
                           }
                        } whereas (restrict > 0);
                }
                catch (TwitterException te) {
                        if (!SFIToolkit.errorDebug(SFIToolkit.
                                stackTraceToString(te)+"n")) {
                                SFIToolkit.errorln("couldn't search tweets");
                        }
                        rc = 606 ;
                }
                return(rc);
        }

non-public static int processData(lengthy obs, Standing tweet_object, Person user_object){
                int                     rc;

                rc = Information.storeStr(1, obs, tweet_object.getText());
                if (rc!=0) return(rc);
                rc = Information.storeNum(2, obs, tweet_object.getRetweetCount());
                if (rc!=0) return(rc);
                rc = Information.storeNum(3, obs, tweet_object.getFavoriteCount());
                if (rc!=0) return(rc);

                rc = Information.storeStr(4, obs, user_object.getName());
                if (rc!=0) return(rc);
                rc = Information.storeNum(5, obs, user_object.getFollowersCount());
                if (rc!=0) return(rc);
                rc = Information.storeNum(6, obs, user_object.getFriendsCount());
                if (rc!=0) return(rc);

                return(rc);
        }

        public static int HelloWorld(String args[]) {
                SFIToolkit.error("Hey World!");
                return(0);
        }
}

Bundling and redistributing the JAR file

There are two primary methods to make the StTwitter class work in Stata.

  1. Copy the Twitter4J .jar information to someplace alongside your adopath. You’ll be able to then use the jar() choice for javacall to specifiy which information to make use of. For instance,

    
    . which twitter4j-core-4.0.4.jar
    c:adopersonaltwitter4j-core-4.0.4.jar
    
    . javacall com.stata.kcrow.StTwitter searchTweets, args("star wars") ///
    jars(test_twitter.jar;twitter4j-core-4.0.4.jar)
    

    I like to recommend this methodology in case you are growing a Java library to your personal use.

  2. Export the venture as a Runnable JAR file

    If you’re growing a Java library for redistribution to someplace just like the Statistical Software program Elements archive, chances are you’ll need to mix all .jar information into one .jar file.

    Click on the Subsequent button, and kind the path/file the place you want to the .jar file saved.

    graph1

    Final, click on the End botton.

    Additionally, be sure you have the right software program license kind to re-distribute any library .jar file.

Parsing in Stata

With our StTwitter class coded and correctly positioned, I can now add parsing to the ado program:


program outline twitter_test
        model 15
        args search_string junk
        if ("`junk'" != "") {
                show as error "invalid syntax"
                exit 198
        }

        javacall com.stata.kcrow.StTwitter searchTweets,                ///
                args(`"`search_string'"')                               ///
                jars(test_twitter.jar;twitter4j-core-4.0.4.jar)
finish

Save the above file as twitter_test.ado alongside your adopath and, in Stata, kind


. twitter_test "star wars"

.describe

Comprises information
  obs:        18,000
 vars:             6
 dimension:     5,436,000
-------------------------------------------------------------------------------
              storage   show    worth
variable identify   kind    format     label      variable label
-------------------------------------------------------------------------------
textual content            str240  %240s
retweet_count   double  %10.0g
favorite_count  double  %10.0g
screen_name     str30   %30s
followers_count double  %10.0g
friends_count   double  %10.0g
-------------------------------------------------------------------------------
Sorted by:
     Observe: Dataset has modified since final saved.

Conclusion

As you’ll be able to see, it didn’t take a lot code to hook up with Twitter’s API, return tweet information, and cargo that information into Stata. Twitter does sale enterprise licenses for his or her information, which haven’t any limits on the quantity of knowledge you’ll be able to obtain. You too can fetch information way back to 2006. There’s a completely different API for this information. The Twitter4J library helps this API as nicely, however the twitter2stata command doesn’t.



Related Articles

Latest Articles