You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2013/04/17 03:47:25 UTC

svn commit: r1468708 - in /tomee/sandbox/tools/src: main/java/org/apache/openejb/tools/twitter/ main/resources/ test/java/org/apache/openejb/tools/

Author: dblevins
Date: Wed Apr 17 01:47:25 2013
New Revision: 1468708

URL: http://svn.apache.org/r1468708
Log:
Revamped retweet tool:
 - logs less : we were getting several gigs a month
 - now considers the people being followed by the accounts, not just those in the contributor list
 - now considers retweets of people in the approved list
 - no longer just approves when hashtag is used, if specific words match (case-sensitive) the tweet will be retweeted

Added:
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Json.java   (with props)
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Key.java   (with props)
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/ObjectMap.java
      - copied, changed from r1457180, tomee/sandbox/release-tools/src/main/java/org/apache/openejb/tools/release/util/ObjectMap.java
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Tweet.java   (with props)
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterApi.java   (with props)
Removed:
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Filters.java
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/JsonResponseParser.java
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/ScreenNamesRetriever.java
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/UserStatusRetriever.java
    tomee/sandbox/tools/src/test/java/org/apache/openejb/tools/RetweetITest.java
Modified:
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Config.java
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Retweet.java
    tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterAccount.java
    tomee/sandbox/tools/src/main/resources/RetweetTool.properties

Modified: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Config.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Config.java?rev=1468708&r1=1468707&r2=1468708&view=diff
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Config.java (original)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Config.java Wed Apr 17 01:47:25 2013
@@ -94,6 +94,10 @@ public class Config {
         return properties.getProperty(account + ".supported.hashtags", "#" + account);
     }
 
+    public static String getWords(String account) {
+        return properties.getProperty(account + ".supported.words", account);
+    }
+
     public static String asString() {
         return properties.toString();
     }

Added: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Json.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Json.java?rev=1468708&view=auto
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Json.java (added)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Json.java Wed Apr 17 01:47:25 2013
@@ -0,0 +1,53 @@
+/*
+ * 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.openejb.tools.twitter;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+* @version $Rev$ $Date$
+*/
+public class Json {
+
+    public static List<Map> asList(String responseBody) {
+        try {
+            final ObjectMapper mapper = new ObjectMapper();
+            return mapper.readValue(new StringReader(responseBody), new TypeReference<ArrayList<Map>>() {
+            });
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public static Map asMap(String responseBody) {
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            return mapper.readValue(new StringReader(responseBody), new TypeReference<Map>() {
+            });
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+}

Propchange: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Json.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Key.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Key.java?rev=1468708&view=auto
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Key.java (added)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Key.java Wed Apr 17 01:47:25 2013
@@ -0,0 +1,33 @@
+/*
+ * 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.openejb.tools.twitter;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @version $Rev$ $Date$
+ */
+@Target({ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Key {
+
+    String value();
+
+}

Propchange: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Key.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/ObjectMap.java (from r1457180, tomee/sandbox/release-tools/src/main/java/org/apache/openejb/tools/release/util/ObjectMap.java)
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/ObjectMap.java?p2=tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/ObjectMap.java&p1=tomee/sandbox/release-tools/src/main/java/org/apache/openejb/tools/release/util/ObjectMap.java&r1=1457180&r2=1468708&rev=1468708&view=diff
==============================================================================
--- tomee/sandbox/release-tools/src/main/java/org/apache/openejb/tools/release/util/ObjectMap.java (original)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/ObjectMap.java Wed Apr 17 01:47:25 2013
@@ -14,26 +14,30 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package org.apache.openejb.tools.release.util;
+package org.apache.openejb.tools.twitter;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.AbstractMap;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 /**
-* @version $Rev$ $Date$
-*/
+ * @version $Rev$ $Date$
+ */
 public class ObjectMap extends AbstractMap<String, Object> {
 
     private final Object object;
-    private Map<String,Entry<String,Object>> attributes;
-    private Set<Entry<String,Object>> entries;
+    private Map<String, Entry<String, Object>> attributes;
+    private Set<Entry<String, Object>> entries;
+    private static final SimpleDateFormat FORMAT = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
 
     public ObjectMap(Object object) {
         this(object.getClass(), object);
@@ -55,7 +59,7 @@ public class ObjectMap extends AbstractM
 
         for (Method getter : clazz.getMethods()) {
             try {
-                if (getter.getName().startsWith("get")) continue;
+                if (!getter.getName().startsWith("get")) continue;
                 if (getter.getParameterTypes().length != 0) continue;
 
 
@@ -101,23 +105,97 @@ public class ObjectMap extends AbstractM
         return entries;
     }
 
-    public class FieldEntry implements Entry<String, Object>  {
+    private Object convert(Object value, Class<?> targetType, final String name) {
+        if (value == null) return value;
+
+        final Class<? extends Object> actualType = value.getClass();
+
+        // Return boxed primitive
+        if (targetType.isPrimitive()) {
+            targetType = boxPrimitive(targetType);
+        }
+
+        // Return if doesn't need converting
+        if (targetType.isAssignableFrom(actualType)){
+            return value;
+        }
+
+        // Return number
+        if (Number.class.isAssignableFrom(actualType) && Number.class.isAssignableFrom(targetType)) {
+            return value;
+        }
+
+        if (Tweet.class.equals(targetType) && Map.class.isAssignableFrom(actualType)) {
+            final Tweet tweet = TwitterApi.asTweet((Map) value);
+            return tweet;
+        }
+
+        // No non-strings beyond this point!!
+        if (!(value instanceof String)) {
+            final String message = String.format("Expected type '%s' for '%s'. Found '%s'", targetType.getName(), name, actualType.getName());
+            throw new IllegalArgumentException(message);
+        }
+
+        final String stringValue = (String) value;
+
+        // Return parsed Enum
+        if (Enum.class.isAssignableFrom(targetType)) {
+            Class<? extends Enum> enumType = (Class<? extends Enum>) targetType;
+            return Enum.valueOf(enumType, stringValue.toUpperCase());
+        }
+
+        // Return parsed Date
+        if (Date.class.equals(targetType)) {
+            // Tue Apr 16 16:01:09 +0000 2013
+            try {
+                return FORMAT.parse(stringValue);
+            } catch (ParseException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }
+
+        // FAIL - not convertable
+        final String message = String.format("Cannot convert to '%s' for '%s'. No PropertyEditor", targetType.getName(), name);
+        throw new IllegalArgumentException(message);
+    }
+
+    private Class<?> boxPrimitive(Class<?> targetType) {
+        if (targetType == byte.class) return Byte.class;
+        if (targetType == char.class) return Character.class;
+        if (targetType == short.class) return Short.class;
+        if (targetType == int.class) return Integer.class;
+        if (targetType == long.class) return Long.class;
+        if (targetType == float.class) return Float.class;
+        if (targetType == double.class) return Double.class;
+        if (targetType == boolean.class) return Boolean.class;
+        return targetType;
+    }
+
+    public class FieldEntry implements Entry<String, Object> {
 
         private final Field field;
+        private final String key;
 
         public FieldEntry(Field field) {
             this.field = field;
+
+            final Key keyAnnotation = field.getAnnotation(Key.class);
+            if (keyAnnotation != null) {
+                this.key = keyAnnotation.value();
+            } else {
+                this.key = field.getName();
+            }
         }
 
         @Override
         public String getKey() {
-            return field.getName();
+            return key;
         }
 
         @Override
-        public String getValue() {
+        public Object getValue() {
             try {
-                return (String) field.get(object);
+                return field.get(object);
             } catch (IllegalAccessException e) {
                 throw new IllegalStateException(e);
             }
@@ -127,6 +205,7 @@ public class ObjectMap extends AbstractM
         public Object setValue(Object value) {
             try {
                 final Object replaced = getValue();
+                value = convert(value, field.getType(), getKey());
                 field.set(object, value);
                 return replaced;
             } catch (IllegalAccessException e) {
@@ -141,15 +220,22 @@ public class ObjectMap extends AbstractM
         private final Method setter;
 
         public MethodEntry(Method getter, Method setter) {
-            StringBuilder name = new StringBuilder(getter.getName());
 
-            // remove 'set' or 'get'
-            name.delete(0, 3);
+            final Key keyAnnotation = getter.getAnnotation(Key.class);
+            if (keyAnnotation != null) {
+                this.key = keyAnnotation.value();
+            } else {
+                StringBuilder name = new StringBuilder(getter.getName());
+
+                // remove 'set' or 'get'
+                name.delete(0, 3);
 
-            // lowercase first char
-            name.setCharAt(0, Character.toLowerCase(name.charAt(0)));
+                // lowercase first char
+                name.setCharAt(0, Character.toLowerCase(name.charAt(0)));
+
+                this.key = name.toString();
+            }
 
-            this.key = name.toString();
             this.getter = getter;
             this.setter = setter;
         }
@@ -177,6 +263,7 @@ public class ObjectMap extends AbstractM
         @Override
         public Object setValue(Object value) {
             final Object original = getValue();
+            value = convert(value, setter.getParameterTypes()[0], getKey());
             invoke(setter, value);
             return original;
         }

Modified: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Retweet.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Retweet.java?rev=1468708&r1=1468707&r2=1468708&view=diff
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Retweet.java (original)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Retweet.java Wed Apr 17 01:47:25 2013
@@ -16,21 +16,13 @@
  */
 package org.apache.openejb.tools.twitter;
 
-import oauth.signpost.exception.OAuthCommunicationException;
-import oauth.signpost.exception.OAuthExpectationFailedException;
-import oauth.signpost.exception.OAuthMessageSignerException;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.log4j.Logger;
 
-import java.io.IOException;
-import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Set;
-
-import static org.apache.openejb.tools.twitter.TwitterAccount.OPENEJB;
+import java.util.concurrent.TimeUnit;
 
 /**
  * We should monitor this feed http://twitter.com/#!/OpenEJB/contributors
@@ -57,73 +49,88 @@ import static org.apache.openejb.tools.t
 public class Retweet {
 
     private static final Logger logger = Logger.getLogger(Retweet.class);
-    public static final String RETWEET_URL = "http://api.twitter.com/1/statuses/retweet/";
 
     public static void main(String[] args) {
 
+        // Everyone in this list will have their tweets considered for retweeting
+        final Set<String> contributorsNames = new HashSet<String>();
+
+        // Add all the OpenEJB contributor list
+        contributorsNames.addAll(TwitterApi.getListMembers("OpenEJB", "contributors"));
+
+        // Add all the people being followed by any of the accounts
         for (TwitterAccount account : TwitterAccount.values()) {
-            final Set<String> validTweetIds = UserStatusRetriever.getAllContributorsStatuses(account);
-            retweetIfNotEmpty(validTweetIds, account);
+            contributorsNames.addAll(TwitterApi.getFriends(account.getScreenName()));
         }
-    }
 
-    private static void retweetIfNotEmpty(Collection<String> tweetIDs, TwitterAccount twitterAccount) {
+        final Set<Tweet> contributorTweets = new HashSet<Tweet>();
 
-        if (!tweetIDs.isEmpty()) {
-            logger.info("About to retweet " + tweetIDs + " at " + twitterAccount.toString() + " twitter account");
-            retweetThisCollectionOfStatuses(tweetIDs, twitterAccount);
-        } else {
-            logger.info("No message to retweet at " + twitterAccount.toString() + " twitter account");
-        }
-    }
+        for (String screenName : contributorsNames) {
+
+            final Set<Tweet> tweets = TwitterApi.getStatuses(screenName);
 
-    private static void retweetThisCollectionOfStatuses(Collection<String> nonRetweetedOpenEJBStatusIDs, TwitterAccount twitterAccount) {
+            contributorTweets.addAll(tweets);
+        }
 
-        for (String statusIDToRetweet : nonRetweetedOpenEJBStatusIDs) {
-            try {
-                retweet(statusIDToRetweet, twitterAccount);
-                pauseBeforeTheNextRetweet();
-            } catch (OAuthMessageSignerException e) {
-                e.printStackTrace();
-            } catch (OAuthExpectationFailedException e) {
-                e.printStackTrace();
-            } catch (OAuthCommunicationException e) {
-                e.printStackTrace();
+        { // Filter out old tweets
+            final Date current = new Date(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(4));
+            final Iterator<Tweet> iterator = contributorTweets.iterator();
+            while (iterator.hasNext()) {
+                final Tweet tweet = iterator.next();
+                if (!tweet.getCreated().after(current)) {
+                    logger.debug("Too old : " + tweet);
+                    iterator.remove();
+                }
             }
         }
-    }
 
+        // Unwrap retweets
+        unwrapRetweets(contributorTweets);
 
-    public static HttpResponse retweet(String statusIDToRetweet, TwitterAccount twitterAccount) throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException {
-        HttpPost httpPost = new HttpPost(RETWEET_URL + statusIDToRetweet + ".json");
+        for (TwitterAccount account : TwitterAccount.values()) {
 
-        twitterAccount.sign(httpPost);
+            final Set<Tweet> tweeted = TwitterApi.getStatuses(account.getScreenName());
 
-        HttpResponse response = null;
-        try {
-            response = getHttpClient().execute(httpPost);
-            logger.debug(response.getStatusLine());
-
-            logger.info("Retweeted " + statusIDToRetweet + " at " + twitterAccount.toString() + " twitter account");
-        } catch (ClientProtocolException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
+            // Unwrap retweets
+            unwrapRetweets(tweeted);
+
+            for (Tweet tweet : contributorTweets) {
+                if (tweeted.contains(tweet)) {
+                    logger.debug("Already tweeted : " + tweet);
+                    continue;
+                }
+
+                if (!account.shouldRetweet(tweet.getText())) {
+                    logger.debug("Doesn't match : " + tweet);
+                    continue;
+                }
+
+                logger.info("Valid : " + tweet);
+                account.queueTweet(tweet);
+
+            }
+
+            // Trigger the retweet thread for this account
+            account.retweet();
         }
 
-        return response;
+        // Retweet threads are non-daemon threads
+        // the system will not exit till they are complete
     }
 
-    public static HttpClient getHttpClient() {
-        return new DefaultHttpClient();
-    }
+    private static void unwrapRetweets(Set<Tweet> tweets) {
+        final Set<Tweet> originalTweets = new HashSet<Tweet>();
 
-    private static void pauseBeforeTheNextRetweet() {
-        try { //So it doesn't look like spamming
-            Thread.sleep(1000 * 60 * 5);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
+        final Iterator<Tweet> iterator = tweets.iterator();
+        while (iterator.hasNext()) {
+            final Tweet tweet = iterator.next();
+            if (tweet.getRetweeted() != null) {
+                logger.debug("Unroll : " + tweet);
+                iterator.remove();
+                originalTweets.add(tweet.getRetweeted());
+            }
         }
-    }
 
+        tweets.addAll(originalTweets);
+    }
 }

Added: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Tweet.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Tweet.java?rev=1468708&view=auto
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Tweet.java (added)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Tweet.java Wed Apr 17 01:47:25 2013
@@ -0,0 +1,90 @@
+/*
+ * 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.openejb.tools.twitter;
+
+import java.util.Date;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class Tweet {
+
+    private long id;
+    private String text;
+    private Date created;
+    private Tweet retweeted;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    @Key("created_at")
+    public Date getCreated() {
+        return created;
+    }
+
+    public void setCreated(Date created) {
+        this.created = created;
+    }
+
+
+    @Key("retweeted_status")
+    public Tweet getRetweeted() {
+        return retweeted;
+    }
+
+    public void setRetweeted(Tweet retweeted) {
+        this.retweeted = retweeted;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Tweet tweet = (Tweet) o;
+
+        if (id != tweet.id) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) (id ^ (id >>> 32));
+    }
+
+    @Override
+    public String toString() {
+        return "Tweet{" +
+                "id=" + id +
+                ", text='" + text + '\'' +
+                '}';
+    }
+}

Propchange: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/Tweet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterAccount.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterAccount.java?rev=1468708&r1=1468707&r2=1468708&view=diff
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterAccount.java (original)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterAccount.java Wed Apr 17 01:47:25 2013
@@ -18,21 +18,27 @@ package org.apache.openejb.tools.twitter
 
 import oauth.signpost.OAuthConsumer;
 import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
-import oauth.signpost.exception.OAuthCommunicationException;
-import oauth.signpost.exception.OAuthExpectationFailedException;
-import oauth.signpost.exception.OAuthMessageSignerException;
-import org.apache.http.HttpRequest;
+import org.apache.log4j.Logger;
 
-import java.util.regex.Matcher;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
 public enum TwitterAccount {
-    OPENEJB, TOMEE;
+    OPENEJB("OpenEJB"), TOMEE("ApacheTomEE");
 
+    private static final Logger logger = Logger.getLogger(TwitterAccount.class);
+
+    private final String screenName;
     private final OAuthConsumer consumer;
-    private final Pattern approvedTweets;
+    private final Pattern hashtags;
+    private final Pattern words;
+    private final List<Tweet> queue = new ArrayList<Tweet>();
+
+    private TwitterAccount(String screenName) {
+        this.screenName = screenName;
 
-    private TwitterAccount() {
         final String account = name().toLowerCase();
 
         // Create the consumer once per account
@@ -41,15 +47,59 @@ public enum TwitterAccount {
 
         // Compile the Pattern once per account
         final String hashTagsSupported = Config.getHashTags(account);
-        approvedTweets = Pattern.compile(".*(#|@)(" + hashTagsSupported + ").*", Pattern.CASE_INSENSITIVE);
+        hashtags = Pattern.compile(".*(#|@)(" + hashTagsSupported + ").*", Pattern.CASE_INSENSITIVE);
+
+        final String wordsSupported = Config.getHashTags(account);
+        words = Pattern.compile(".*(" + wordsSupported + ").*");
+    }
+
+    public String getScreenName() {
+        return screenName;
     }
 
     public boolean shouldRetweet(String tweet) {
-        final Matcher matcher = approvedTweets.matcher(tweet);
-        return matcher.matches();
+        return words.matcher(tweet).matches() || hashtags.matcher(tweet).matches();
     }
 
-    public void sign(HttpRequest request) throws OAuthExpectationFailedException, OAuthMessageSignerException, OAuthCommunicationException {
-        consumer.sign(request);
+    public synchronized void queueTweet(Tweet tweet) {
+        queue.add(tweet);
     }
+
+    public synchronized void retweet() {
+        // copy then clear the original list
+        final List<Tweet> retweet = new ArrayList<Tweet>(this.queue);
+        this.queue.clear();
+
+        // Non-daemon thread prevents vm exit till all tweets are completed
+        new Thread() {
+            @Override
+            public void run() {
+                for (Tweet tweet : retweet) {
+                    try {
+
+                        final long tweetId = tweet.getId();
+
+                        TwitterApi.retweet(consumer, tweetId);
+
+                        logger.info(TwitterAccount.this.getScreenName() + " Retweeted " + tweet);
+
+                        pauseBeforeTheNextRetweet();
+
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+
+        }.start();
+    }
+
+    private static void pauseBeforeTheNextRetweet() {
+        try { //So it doesn't look like spamming
+            Thread.sleep(TimeUnit.MINUTES.toMillis(5));
+        } catch (InterruptedException e) {
+            Thread.interrupted();
+        }
+    }
+
 }

Added: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterApi.java
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterApi.java?rev=1468708&view=auto
==============================================================================
--- tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterApi.java (added)
+++ tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterApi.java Wed Apr 17 01:47:25 2013
@@ -0,0 +1,127 @@
+/*
+ * 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.openejb.tools.twitter;
+
+import oauth.signpost.OAuthConsumer;
+import oauth.signpost.exception.OAuthCommunicationException;
+import oauth.signpost.exception.OAuthExpectationFailedException;
+import oauth.signpost.exception.OAuthMessageSignerException;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class TwitterApi {
+
+    public static void retweet(OAuthConsumer account, long tweetId) throws OAuthMessageSignerException, OAuthExpectationFailedException, OAuthCommunicationException, IOException {
+
+        final String uri = "http://api.twitter.com/1/statuses/retweet/" + tweetId + ".json";
+        final HttpUriRequest httpPost = new HttpPost(uri);
+
+        account.sign(httpPost);
+        execute(httpPost);
+    }
+
+    public static List<String> getListMembers(final String screenName, final String listName) {
+        final String uri = "http://api.twitter.com/1/lists/members.json?slug=" + listName + "&owner_screen_name=" + screenName;
+        return getScreenNames(uri);
+    }
+
+    public static List<String> getFriends(final String screenName) {
+        final String uri = "http://api.twitter.com/1/friends.json?screen_name=" + screenName;
+        return getScreenNames(uri);
+    }
+
+    private static List<String> getScreenNames(String uri) {
+        try {
+            final String responseBody = get(uri);
+            final Map response = Json.asMap(responseBody);
+
+            final List<Map> users = (List<Map>) response.get("users");
+            final List<String> contributorsScreenNames = new ArrayList<String>();
+
+            for (Map map : users) {
+                contributorsScreenNames.add((String) map.get("screen_name"));
+            }
+
+            return contributorsScreenNames;
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public static Set<Tweet> getStatuses(String screenName) {
+        try {
+            final String uri = "http://api.twitter.com/1/statuses/user_timeline.json?include_rts=true&count=20&screen_name=" + screenName;
+            final String responseBody = get(uri);
+            final List<Map> result = Json.asList(responseBody);
+
+            return asTweets(result);
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to get statuses for screenName: " + screenName, e);
+        }
+    }
+
+    private static String get(String uri) throws IOException {
+        final HttpUriRequest httpGet = new HttpGet(uri);
+        return execute(httpGet);
+    }
+
+    private static String execute(HttpUriRequest request) throws IOException {
+        final DefaultHttpClient client = new DefaultHttpClient();
+        final HttpResponse response = client.execute(request);
+
+        final ResponseHandler<String> responseHander = new BasicResponseHandler();
+        return responseHander.handleResponse(response);
+    }
+
+    private static Set<Tweet> asTweets(List<Map> listFromJson) {
+        final Set<Tweet> tweets = new HashSet<Tweet>();
+        for (Map from : listFromJson) {
+
+            final Tweet tweet = asTweet(from);
+
+            tweets.add(tweet);
+        }
+        return tweets;
+    }
+
+    public static Tweet asTweet(Map from) {
+        final Tweet tweet = new Tweet();
+
+        final ObjectMap to = new ObjectMap(tweet);
+        for (String key : to.keySet()) {
+            if (from.containsKey(key)) {
+                to.put(key, from.get(key));
+            }
+        }
+        return tweet;
+    }
+}

Propchange: tomee/sandbox/tools/src/main/java/org/apache/openejb/tools/twitter/TwitterApi.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomee/sandbox/tools/src/main/resources/RetweetTool.properties
URL: http://svn.apache.org/viewvc/tomee/sandbox/tools/src/main/resources/RetweetTool.properties?rev=1468708&r1=1468707&r2=1468708&view=diff
==============================================================================
--- tomee/sandbox/tools/src/main/resources/RetweetTool.properties (original)
+++ tomee/sandbox/tools/src/main/resources/RetweetTool.properties Wed Apr 17 01:47:25 2013
@@ -15,4 +15,6 @@ retweetApp.tomee.authorizedUser.consumer
 
 # pipe separated list of hashtags
 openejb.supported.hashtags=openejb|tomee
+openejb.supported.words=OpenEJB|TomEE
 tomee.supported.hashtags=apachetomee|tomee|openjpa|myfaces|openwebbeans|owb|tomcat|openejb
+tomee.supported.words=OpenEJB|TomEE