| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.asterix.external.util; |
| |
| import org.apache.asterix.common.exceptions.AsterixException; |
| import twitter4j.FilterQuery; |
| import twitter4j.Twitter; |
| import twitter4j.TwitterFactory; |
| import twitter4j.TwitterStream; |
| import twitter4j.TwitterStreamFactory; |
| import twitter4j.conf.ConfigurationBuilder; |
| |
| import java.io.InputStream; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| public class TwitterUtil { |
| |
| private static Logger LOGGER = Logger.getLogger(TwitterUtil.class.getName()); |
| |
| public static class ConfigurationConstants { |
| public static final String KEY_LOCATIONS = "locations"; // locations to track |
| public static final String KEY_LOCATION = "location"; // location to track |
| public static final String LOCATION_US = "US"; |
| public static final String LOCATION_EU = "Europe"; |
| public static final String LANGUAGES = "languages"; // languages to track |
| public static final String TRACK = "keywords"; // terms to track |
| public static final String FILTER_LEVEL = "filter-level"; |
| } |
| |
| public static class GeoConstants { |
| private static final double[][] US = new double[][] { { -124.848974, 24.396308 }, { -66.885444, 49.384358 } }; |
| private static final double[][] EU = new double[][] { { -29.7, 36.7 }, { 79.2, 72.0 } }; |
| public static Map<String, double[][]> boundingBoxes = initializeBoundingBoxes(); |
| } |
| |
| private static Map<String, double[][]> initializeBoundingBoxes() { |
| Map<String, double[][]> boundingBoxes = new HashMap<String, double[][]>(); |
| boundingBoxes.put(ConfigurationConstants.LOCATION_US, GeoConstants.US); |
| boundingBoxes.put(ConfigurationConstants.LOCATION_EU, GeoConstants.EU); |
| return boundingBoxes; |
| } |
| |
| /** |
| * Gets more than one bounding box from a sequences of coordinates |
| * (following Twitter formats) + predefined location names, as US and EU. |
| * |
| * E.g., for EU and US, we would use -29.7, 79.2, 36.7, 72.0; -124.848974, |
| * -66.885444, 24.396308, 49.384358. |
| * |
| * @param locationValue |
| * String value of the location coordinates or names (comma-separated) |
| * @return |
| * @throws AsterixException |
| */ |
| public static double[][] getBoundingBoxes(String locationValue) throws AsterixException { |
| double[][] locations = null; |
| |
| String coordRegex = "^((((\\-?\\d+\\.\\d+),\\s*){3}(\\-?\\d+\\.\\d+)|\\w+);\\s*)*(((\\-?\\d+\\.\\d+),\\s*){3}(\\-?\\d+\\.\\d+)|\\w+)$"; |
| Pattern p = Pattern.compile(coordRegex); |
| Matcher m = p.matcher(locationValue); |
| |
| if (m.matches()) { |
| String[] locationStrings = locationValue.trim().split(";\\s*"); |
| locations = new double[locationStrings.length * 2][2]; |
| |
| for (int i = 0; i < locationStrings.length; i++) { |
| if (locationStrings[i].contains(",")) { |
| String[] coordinatesString = locationStrings[i].split(","); |
| for (int k = 0; k < 2; k++) { |
| for (int l = 0; l < 2; l++) { |
| try { |
| locations[2 * i + k][l] = Double.parseDouble(coordinatesString[2 * k + l]); |
| } catch (NumberFormatException ne) { |
| throw new AsterixException( |
| "Incorrect coordinate value " + coordinatesString[2 * k + l]); |
| } |
| } |
| } |
| } else if (GeoConstants.boundingBoxes.containsKey(locationStrings[i])) { |
| // Only add known locations |
| double loc[][] = GeoConstants.boundingBoxes.get(locationStrings[i]); |
| for (int k = 0; k < 2; k++) { |
| for (int l = 0; l < 2; l++) { |
| locations[2 * i + k][l] = loc[k][l]; |
| } |
| } |
| } |
| } |
| } |
| return locations; |
| } |
| |
| public static FilterQuery getFilterQuery(Map<String, String> configuration) throws AsterixException { |
| String locationValue = null; |
| |
| // For backward compatibility |
| if (configuration.containsKey(ConfigurationConstants.KEY_LOCATIONS)) { |
| locationValue = configuration.get(ConfigurationConstants.KEY_LOCATIONS); |
| } else { |
| locationValue = configuration.get(ConfigurationConstants.KEY_LOCATION); |
| } |
| String langValue = configuration.get(ConfigurationConstants.LANGUAGES); |
| String trackValue = configuration.get(ConfigurationConstants.TRACK); |
| |
| FilterQuery filterQuery = null; |
| |
| // Terms to track |
| if (trackValue != null) { |
| String keywords[] = null; |
| filterQuery = new FilterQuery(); |
| if (trackValue.contains(",")) { |
| keywords = trackValue.trim().split(",\\s*"); |
| } else { |
| keywords = new String[] { trackValue }; |
| } |
| filterQuery = filterQuery.track(keywords); |
| } |
| |
| // Language filtering parameter |
| if (langValue != null) { |
| if (filterQuery == null) { |
| filterQuery = new FilterQuery(); |
| } |
| String languages[]; |
| if (langValue.contains(",")) { |
| languages = langValue.trim().split(",\\s*"); |
| } else { |
| languages = new String[] { langValue }; |
| } |
| filterQuery = filterQuery.language(languages); |
| } |
| |
| // Location filtering parameter |
| if (locationValue != null) { |
| double[][] locations = getBoundingBoxes(locationValue); |
| if (locations != null) { |
| if (filterQuery == null) { |
| filterQuery = new FilterQuery(); |
| } |
| filterQuery = filterQuery.locations(locations); |
| } |
| } |
| |
| // Filtering level: none, low or medium (defaul=none) |
| if (filterQuery != null) { |
| String filterValue = configuration.get(ConfigurationConstants.FILTER_LEVEL); |
| if (filterValue != null) { |
| filterQuery = filterQuery.filterLevel(filterValue); |
| } |
| } |
| |
| return filterQuery; |
| |
| } |
| |
| public static Twitter getTwitterService(Map<String, String> configuration) { |
| ConfigurationBuilder cb = getAuthConfiguration(configuration); |
| TwitterFactory tf = null; |
| try { |
| tf = new TwitterFactory(cb.build()); |
| } catch (Exception e) { |
| if (LOGGER.isLoggable(Level.WARNING)) { |
| StringBuilder builder = new StringBuilder(); |
| builder.append("Twitter Adapter requires the following config parameters\n"); |
| builder.append(AuthenticationConstants.OAUTH_CONSUMER_KEY + "\n"); |
| builder.append(AuthenticationConstants.OAUTH_CONSUMER_SECRET + "\n"); |
| builder.append(AuthenticationConstants.OAUTH_ACCESS_TOKEN + "\n"); |
| builder.append(AuthenticationConstants.OAUTH_ACCESS_TOKEN_SECRET + "\n"); |
| LOGGER.warning(builder.toString()); |
| LOGGER.warning( |
| "Unable to configure Twitter adapter due to incomplete/incorrect authentication credentials"); |
| LOGGER.warning( |
| "For details on how to obtain OAuth authentication token, visit https://dev.twitter.com/oauth" |
| + "/overview/application-owner-access-tokens"); |
| } |
| } |
| Twitter twitter = tf.getInstance(); |
| return twitter; |
| } |
| |
| public static TwitterStream getTwitterStream(Map<String, String> configuration) { |
| ConfigurationBuilder cb = getAuthConfiguration(configuration); |
| TwitterStreamFactory factory = new TwitterStreamFactory(cb.build()); |
| return factory.getInstance(); |
| } |
| |
| private static ConfigurationBuilder getAuthConfiguration(Map<String, String> configuration) { |
| ConfigurationBuilder cb = new ConfigurationBuilder(); |
| cb.setDebugEnabled(true); |
| cb.setJSONStoreEnabled(true); |
| String oAuthConsumerKey = configuration.get(AuthenticationConstants.OAUTH_CONSUMER_KEY); |
| String oAuthConsumerSecret = configuration.get(AuthenticationConstants.OAUTH_CONSUMER_SECRET); |
| String oAuthAccessToken = configuration.get(AuthenticationConstants.OAUTH_ACCESS_TOKEN); |
| String oAuthAccessTokenSecret = configuration.get(AuthenticationConstants.OAUTH_ACCESS_TOKEN_SECRET); |
| |
| cb.setOAuthConsumerKey(oAuthConsumerKey); |
| cb.setOAuthConsumerSecret(oAuthConsumerSecret); |
| cb.setOAuthAccessToken(oAuthAccessToken); |
| cb.setOAuthAccessTokenSecret(oAuthAccessTokenSecret); |
| return cb; |
| } |
| |
| public static void initializeConfigurationWithAuthInfo(Map<String, String> configuration) throws AsterixException { |
| String authMode = configuration.get(AuthenticationConstants.AUTHENTICATION_MODE); |
| if (authMode == null) { |
| authMode = AuthenticationConstants.AUTHENTICATION_MODE_FILE; |
| } |
| try { |
| switch (authMode) { |
| case AuthenticationConstants.AUTHENTICATION_MODE_FILE: |
| Properties prop = new Properties(); |
| String authFile = configuration.get(AuthenticationConstants.OAUTH_AUTHENTICATION_FILE); |
| if (authFile == null) { |
| authFile = AuthenticationConstants.DEFAULT_AUTH_FILE; |
| } |
| InputStream in = TwitterUtil.class.getResourceAsStream(authFile); |
| prop.load(in); |
| in.close(); |
| configuration.put(AuthenticationConstants.OAUTH_CONSUMER_KEY, |
| prop.getProperty(AuthenticationConstants.OAUTH_CONSUMER_KEY)); |
| configuration.put(AuthenticationConstants.OAUTH_CONSUMER_SECRET, |
| prop.getProperty(AuthenticationConstants.OAUTH_CONSUMER_SECRET)); |
| configuration.put(AuthenticationConstants.OAUTH_ACCESS_TOKEN, |
| prop.getProperty(AuthenticationConstants.OAUTH_ACCESS_TOKEN)); |
| configuration.put(AuthenticationConstants.OAUTH_ACCESS_TOKEN_SECRET, |
| prop.getProperty(AuthenticationConstants.OAUTH_ACCESS_TOKEN_SECRET)); |
| break; |
| case AuthenticationConstants.AUTHENTICATION_MODE_EXPLICIT: |
| break; |
| } |
| } catch (Exception e) { |
| if (LOGGER.isLoggable(Level.WARNING)) { |
| LOGGER.warning("unable to load authentication credentials from auth.properties file" |
| + "credential information will be obtained from adapter's configuration"); |
| } |
| } |
| } |
| |
| public static final class AuthenticationConstants { |
| public static final String OAUTH_CONSUMER_KEY = "consumer.key"; |
| public static final String OAUTH_CONSUMER_SECRET = "consumer.secret"; |
| public static final String OAUTH_ACCESS_TOKEN = "access.token"; |
| public static final String OAUTH_ACCESS_TOKEN_SECRET = "access.token.secret"; |
| public static final String OAUTH_AUTHENTICATION_FILE = "authentication.file"; |
| public static final String AUTHENTICATION_MODE = "authentication.mode"; |
| public static final String AUTHENTICATION_MODE_FILE = "file"; |
| public static final String AUTHENTICATION_MODE_EXPLICIT = "explicit"; |
| public static final String DEFAULT_AUTH_FILE = "/feed/twitter/auth.properties"; // default authentication file |
| } |
| |
| public static final class SearchAPIConstants { |
| public static final String QUERY = "query"; |
| public static final String INTERVAL = "interval"; |
| } |
| |
| } |