From 784229d0f41a4272ad1c40a63e4603bc8629ec01 Mon Sep 17 00:00:00 2001 From: Maurice Laveaux Date: Wed, 23 Apr 2014 16:10:43 +0200 Subject: Implemented Authorization with twitter. Started working on getProfile for a given username. --- src/data/Profile.java | 16 ++++ src/data/Tweet.java | 9 ++ src/gui/MainFrame.form | 54 +++++++++++ src/gui/MainFrame.java | 100 ++++++++++++++++++++ src/main/Main.java | 14 +++ src/mining/Authentication.java | 206 +++++++++++++++++++++++++++++++++++++++++ src/mining/Miner.java | 25 +++++ src/mining/Search.java | 118 +++++++++++++++++++++++ src/mining/Stream.java | 9 ++ 9 files changed, 551 insertions(+) create mode 100644 src/data/Profile.java create mode 100644 src/data/Tweet.java create mode 100644 src/gui/MainFrame.form create mode 100644 src/gui/MainFrame.java create mode 100644 src/main/Main.java create mode 100644 src/mining/Authentication.java create mode 100644 src/mining/Miner.java create mode 100644 src/mining/Search.java create mode 100644 src/mining/Stream.java diff --git a/src/data/Profile.java b/src/data/Profile.java new file mode 100644 index 0000000..e4ba602 --- /dev/null +++ b/src/data/Profile.java @@ -0,0 +1,16 @@ + +package data; + +/** + * This class contains the data that is stored of a user. + */ +public class Profile { + + private boolean m_exists; + + private String m_name; + + private String m_realName; + + private String m_creationDate; +} diff --git a/src/data/Tweet.java b/src/data/Tweet.java new file mode 100644 index 0000000..ebaabf3 --- /dev/null +++ b/src/data/Tweet.java @@ -0,0 +1,9 @@ + +package data; + +/** + * This class contains the data that is stored within a Tweet. + */ +public class Tweet { + +} diff --git a/src/gui/MainFrame.form b/src/gui/MainFrame.form new file mode 100644 index 0000000..a972587 --- /dev/null +++ b/src/gui/MainFrame.form @@ -0,0 +1,54 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/gui/MainFrame.java b/src/gui/MainFrame.java new file mode 100644 index 0000000..2e82fc6 --- /dev/null +++ b/src/gui/MainFrame.java @@ -0,0 +1,100 @@ +package gui; + + +/** + * + * @author maurice + */ +public class MainFrame extends javax.swing.JFrame { + + /** + * Creates new form MainFrame + */ + public MainFrame() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jButton1 = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + jButton1.setText("Authenticate"); + jButton1.setActionCommand("Authenticate"); + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jButton1) + .addContainerGap(470, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(jButton1) + .addContainerGap(369, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_jButton1ActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + /* Set the Nimbus look and feel */ + // + /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. + * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html + */ + try { + for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + javax.swing.UIManager.setLookAndFeel(info.getClassName()); + break; + } + } + } catch (ClassNotFoundException ex) { + java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (InstantiationException ex) { + java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (IllegalAccessException ex) { + java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } catch (javax.swing.UnsupportedLookAndFeelException ex) { + java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } + // + + /* Create and display the form */ + java.awt.EventQueue.invokeLater(new Runnable() { + public void run() { + new MainFrame().setVisible(true); + } + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + // End of variables declaration//GEN-END:variables +} diff --git a/src/main/Main.java b/src/main/Main.java new file mode 100644 index 0000000..f9b0cec --- /dev/null +++ b/src/main/Main.java @@ -0,0 +1,14 @@ +package main; + +import mining.Miner; + +/** + * + */ +public class Main { + + public static void main(String[] args) + { + Miner miner = new Miner(); + } +} diff --git a/src/mining/Authentication.java b/src/mining/Authentication.java new file mode 100644 index 0000000..d68843a --- /dev/null +++ b/src/mining/Authentication.java @@ -0,0 +1,206 @@ +package mining; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Scanner; +import java.util.logging.Level; +import java.util.logging.Logger; + +import oauth.signpost.OAuth; +import oauth.signpost.OAuthConsumer; +import oauth.signpost.OAuthProvider; +import oauth.signpost.basic.DefaultOAuthConsumer; +import oauth.signpost.basic.DefaultOAuthProvider; +import oauth.signpost.exception.OAuthCommunicationException; +import oauth.signpost.exception.OAuthException; +import oauth.signpost.exception.OAuthExpectationFailedException; +import oauth.signpost.exception.OAuthMessageSignerException; +import oauth.signpost.exception.OAuthNotAuthorizedException; + +import utils.Configuration; + +/** + * This class uses the Open Authentication API to register the application with + * twitter.com, before obtaining data. + */ +public class Authentication { + + // the consumer to sign http requests with. + private final OAuthConsumer m_consumer; + + // the public access token of this application. + private String m_accessToken = "unknown"; + + // the secret access token of this application. + private String m_secretToken = "unknown"; + + /** + * Authenticates the application and else throws exception. + * + * @param consumerKey The key that was returned for the application. + * @param consumerSecret The secret that was returned for the application. + */ + public Authentication(final String consumerKey, final String consumerSecret) throws IOException { + final String savefile = "stored_tokens.txt"; + + try { + // Obtain the last stored tokens. + load(savefile); + } catch (FileNotFoundException ex) { + // Create the file when it doesn't exist. + save(savefile); + } + + // consumer (this application keys) given to the provider. + m_consumer = new DefaultOAuthConsumer(Configuration.CONSUMER_KEY, Configuration.CONSUMER_SECRET); + + // set the stored authentication tokens. + m_consumer.setTokenWithSecret(m_accessToken, m_secretToken); + + // Try if the authentication is successfull + if (isAuthenticated()) { + System.out.println("Authentication granted."); + return; + } + + // full authentication for the server. + fullAuthenticate(consumerKey, consumerSecret); + + // Try if the authentication is successfull + if (!isAuthenticated()) { + throw new RuntimeException("Authentication fails after succeeding."); + } else { + System.out.println("Authentication granted."); + } + + // save the obtained tokens. + save(savefile); + } + + /** + * + * @param consumerKey The given consumer key for the program. + * @param secretKey The given secret key for the program. + * @param savefile + * @throws RuntimeException + */ + private void fullAuthenticate(final String consumerKey, final String consumerSecret) throws RuntimeException { + try { + //consumer key for Twitter Data Analytics application + if (consumerKey.isEmpty()) { + throw new RuntimeException("OAuthUtils.CONSUMER_KEY was not set, Register an application " + + "and copy the consumer key into the configuration file."); + } + + //consumer key for Twitter Data Analytics application + if (consumerSecret.isEmpty()) { + throw new RuntimeException("OAuthUtils.CONSUMER_SECRET was not set, Register an application " + + "and copy the consumer secret into the configuration file."); + } + + // Provides the open authentication. + OAuthProvider provider = new DefaultOAuthProvider(Configuration.REQUEST_TOKEN_URL, Configuration.ACCESS_TOKEN_URL, Configuration.AUTHORIZE_URL); + + // retrieve the url to authenticate this program with. + String authUrl = provider.retrieveRequestToken(m_consumer, OAuth.OUT_OF_BAND); + + System.out.println("Now visit:\n" + authUrl + "\n and grant this app authorization"); + System.out.println("Enter the PIN code and hit ENTER when you're done:"); + + // read the next line to retrieve the pin code from the user. + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + String pin = br.readLine(); + + System.out.println("Fetching access token from Twitter"); + + provider.retrieveAccessToken(m_consumer, pin); + + // obtain the given access token and access secret. + m_accessToken = m_consumer.getToken(); + m_secretToken = m_consumer.getTokenSecret(); + + } catch (IOException | OAuthException ex) { + Logger.getLogger(Authentication.class.getName()).log(Level.SEVERE, null, ex); + } + } + + /** + * Signs the http request with the given authentication. + * + * @param object Any object, because why not? + * @throws oauth.signpost.exception.OAuthMessageSignerException + * @throws oauth.signpost.exception.OAuthExpectationFailedException + * @throws oauth.signpost.exception.OAuthCommunicationException + */ + public void sign(Object object) + throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException { + m_consumer.sign(object); + } + + /** + * Store the given tokens in a file. + */ + private void save(final String filename) throws IOException { + final String newLine = System.getProperty("line.separator"); + + // open the given filename file. + File file = new File(filename); + try (BufferedWriter output = new BufferedWriter(new FileWriter(file))) { + output.write(m_accessToken + newLine + m_secretToken); + } + } + + /** + * Retrieve the given tokens from a file. + */ + private void load(final String filename) throws FileNotFoundException { + // open the given filename file. + File inFile = new File(filename); + + // create a scanner for the tokens. + Scanner scanner = new Scanner(inFile); + + // Read the first and second lines for the tokens. + m_accessToken = scanner.nextLine(); + m_accessToken = scanner.nextLine(); + } + + private boolean isAuthenticated() { + try { + // Step 1: Open a http connection to + // https://api.twitter.com/1.1/users/show.json?screen_name= + // with a read timeout of 5 seconds. + URL url = new URL("https://api.twitter.com/1.1/users/show.json?screen_name=maskman113"); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setReadTimeout(5000); + + // Step 2: Sign the request using the OAuth Secret + sign(urlConnection); + + // try to connect to this url address. + urlConnection.connect(); + + // obtain the respons of the connection. + int responseCode = urlConnection.getResponseCode(); + + if (responseCode == 401) { + // Bad authentication. + return false; + } + } catch (MalformedURLException ex) { + Logger.getLogger(Authentication.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException | OAuthMessageSignerException | OAuthExpectationFailedException | OAuthCommunicationException ex) { + Logger.getLogger(Authentication.class.getName()).log(Level.SEVERE, null, ex); + } + + return true; + } +} diff --git a/src/mining/Miner.java b/src/mining/Miner.java new file mode 100644 index 0000000..e21da09 --- /dev/null +++ b/src/mining/Miner.java @@ -0,0 +1,25 @@ +package mining; + +import java.io.IOException; +import utils.Configuration; + +/** + * The main data mining object. + */ +public class Miner { + + // the main class to authenticate the application. + private Authentication m_auth; + + // main miner to search data of users and tweets. + private Search m_search; + + public Miner() throws IOException + { + // Authentication such that the miner can request data. + m_auth = new Authentication(Configuration.CONSUMER_KEY, Configuration.CONSUMER_SECRET); + + // create a new search object. + m_search = new Search(m_auth); + } +} diff --git a/src/mining/Search.java b/src/mining/Search.java new file mode 100644 index 0000000..68f2a48 --- /dev/null +++ b/src/mining/Search.java @@ -0,0 +1,118 @@ +package mining; + +import data.Profile; +import java.io.BufferedReader; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; +import oauth.signpost.exception.OAuthCommunicationException; +import oauth.signpost.exception.OAuthException; +import oauth.signpost.exception.OAuthExpectationFailedException; +import oauth.signpost.exception.OAuthMessageSignerException; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Retrieve data from twitter.com by explicitly searching for it. + */ +public class Search { + + // the class to use for authentication of the http connection. + private final Authentication m_auth; + + public Search(Authentication auth) { + m_auth = auth; + + getProfile("maskman113"); + } + + /** + * Retrieves the profile information of the user + * + * @param username of the user whose profile needs to be retrieved + * @return the profile information as profile object. + */ + public Profile getProfile(String username) { + BufferedReader bRead = null; + JSONObject profile = null; + + boolean retry = false; + + try { + System.out.println("Receiving profile of " + username); + + // Step 1: Open a http connection to + // https://api.twitter.com/1.1/users/show.json?screen_name= + // with a read timeout of 5 seconds. + URL url = new URL("https://api.twitter.com/1.1/users/show.json?screen_name=" + username); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + urlConnection.setReadTimeout(5000); + + // Step 2: Sign the request using the OAuth Secret + m_auth.sign(urlConnection); + + // try to connect to this url address. + urlConnection.connect(); + + // obtain the respons of the connection. + int responseCode = urlConnection.getResponseCode(); + + if (responseCode == 404 || responseCode == 401) { + // Could not find host. + System.err.println("Connection failed, error: " + responseCode); + } else if (responseCode == 500 || responseCode == 502 || responseCode == 503) { + // Internal Server Error. + disconnect(urlConnection, responseCode); + } // Server quota has been reached. + else if (responseCode == 429) { + disconnect(urlConnection, responseCode); + try { + // Sleep until more requests are available. + Thread.sleep(1000); + } catch (InterruptedException ex) { + Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex); + } + retry = true; + } + + if (retry) { + //recreate the connection because only the amount of requests was too much. + urlConnection.connect(); + } + + StringBuilder content = new StringBuilder(); + + urlConnection.disconnect(); + + try { + profile = new JSONObject(content.toString()); + + System.out.println(profile.toString()); + } catch (JSONException ex) { + System.err.println(ex); + } + } catch (OAuthException | IOException ex) { + System.err.println(ex); + } + + return new Profile(); + } + + public void searchTags() { + + } + + private void disconnect(HttpURLConnection urlConnection, int responseCode) { + try { + // Try to disconnect the connection. + urlConnection.disconnect(); + System.out.println(responseCode); + Thread.sleep(3000); + } catch (InterruptedException ex) { + // Closing the connection failed.... + System.err.println("Closing connection failed: " + ex.getMessage()); + } + } +} diff --git a/src/mining/Stream.java b/src/mining/Stream.java new file mode 100644 index 0000000..c9c08f0 --- /dev/null +++ b/src/mining/Stream.java @@ -0,0 +1,9 @@ + +package mining; + +/** + * This miner obtains data by receiving a stream from twitter. + */ +public class Stream { + +} -- cgit v1.2.1