/*******************************************************************************
* Copyright 2010 Universidade do Minho, Ricardo Vila�a and Francisco Cruz
*
* Licensed 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.ublog.benchmark.social.cassandra;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.ublog.utils.Pair;
import org.ublog.benchmark.BenchOperation;
import org.ublog.benchmark.ComplexBenchMarkClient;
import org.ublog.benchmark.operations.CollectionOperation;
import org.ublog.benchmark.operations.DataStoreOperation;
import org.ublog.benchmark.operations.GetOperation;
import org.ublog.benchmark.operations.MultiPutOperation;
import org.ublog.benchmark.operations.OperationListener;
import org.ublog.benchmark.operations.PutOperation;
import org.ublog.benchmark.social.Message;
import org.ublog.benchmark.social.SocialBenchmark;
import org.ublog.benchmark.social.UserService;
import org.ublog.benchmark.social.Utils;
public class TweetOperation implements BenchOperation, OperationListener {
private Logger logger = Logger.getLogger(TweetOperation.class);
private enum Phase {
USER, TWEET, FOLLOWERS
};
private Phase phase;
private boolean get;
private boolean finish;
private ComplexBenchMarkClient client;
private Message tweet;
private Map<String, String> tweetMap;
private Map<String, String> user;
private String tweetId;
private Set<String> followers;
private Map<String, Pair<List<String>, List<Integer>>> mapTimeLine;
private Map<String, Pair<String, Object>> tweetFriendsTimeline;
private Set<String> tags;
private boolean init;
public TweetOperation(ComplexBenchMarkClient client, Message tweet,
Set<String> tags) {
this.client = client;
this.tweet = tweet;
this.phase = Phase.USER;
this.get = false;
this.finish = false;
this.user = null;
this.mapTimeLine = null;
this.tags = tags;
this.setInit(false);
logger.setLevel(Level.OFF);
}
private void insertTweet() {
String dateStr = tweetMap.get(Utils.DATE);
Long date = new Long(dateStr);
String timelineId = tweetId + ":" + dateStr;
cycle: // ////
for (String key : this.mapTimeLine.keySet()) {
List<String> timeLine = this.mapTimeLine.get(key).getFirst();
for (int i = 0; i < timeLine.size(); i++) {
String id = timeLine.get(i/* 0 */);
String[] split = id.split(":");
Long timelineDate = new Long(split[1]);
if (timelineDate < date) {
timeLine.add(i, timelineId);
continue cycle;// ////
// return;
}
}
timeLine.add(timelineId);
}
}
@SuppressWarnings("unchecked")
private void setTweetToFriendsTimeLine() {
String dateStr = tweetMap.get(Utils.DATE);
String timelineId = tweetId + ":" + dateStr;
this.tweetFriendsTimeline = new HashMap<String, Pair<String, Object>>();
for (String follower : this.followers) {
this.tweetFriendsTimeline.put(follower, new Pair(dateStr,
timelineId));
}
}
@SuppressWarnings("unchecked")
@Override
public void handleFinishedOperation(DataStoreOperation op) {
switch (this.phase) {
case USER:
if (this.user == null) {
this.user = (Map<String, String>) ((GetOperation) op)
.getResult();
if (this.user == null) {
this.finish = true;
} else {
this.followers = Utils.asSet(user
.get(UserService.FOLLOWERS));
// Also update my timeLine
this.followers.add(this.tweet.getUser());
}
} else
this.phase = Phase.TWEET;
break;
case TWEET:
this.phase = Phase.FOLLOWERS;
break;
case FOLLOWERS:
/*
* if (this.mapTimeLine==null) { this.mapTimeLine=new
* HashMap<String, Pair<List<String>,List<Integer>>>();
* Map<String,Object> res=((MultiGetOperation<String>)
* op).getResult(); for (String key:this.followers) { List<Integer>
* tags=new ArrayList<Integer>(); tags.add(Utils.getTagUserID(key));
* if (res.containsKey(key)) this.mapTimeLine.put(key, new
* Pair<List<
* String>,List<Integer>>((List<String>)res.get(key),tags)); else {
* //Create empty timeLine for user this.mapTimeLine.put(key, new
* Pair<List<String>,List<Integer>>(new ArrayList<String>(),tags));
* } } insertTweet(); } else {
*/
if (!init)
this.client.handleFinishedComplexOperation(this);
// }
break;
}
}
@Override
public String getName() {
return "twitter:tweet";
}
@Override
public CollectionOperation getNextDBOperation()
throws UnsupportedEncodingException {
CollectionOperation res = null;
switch (this.phase) {
case USER:
if (!this.get) {
tweet.setDate(Utils.getTimeUUID());
this.tweetMap = Utils.toMap(tweet);
String userId = tweet.getUser();
// CASSANDRA: GET SPECIFIED COLUMNS
List<byte[]> columns = new ArrayList<byte[]>();
columns.add("lastTweet".getBytes("UTF-8"));
columns.add("followers".getBytes("UTF-8"));
// /FINISH
res = new GetOperation(client, SocialBenchmark.userTable,
userId, columns);
this.get = true;
} else {
String lastTweetStr = user.get(UserService.LAST_TWEET);
// System.out.println("TweetOp lastTweetstr:"+lastTweetStr);
int lastTweet = Integer.valueOf(lastTweetStr);
int tweetIdx = ++lastTweet;
user.put(UserService.LAST_TWEET,
new Integer(tweetIdx).toString());
this.tweetId = tweet.getUser() + "-"
+ Utils.getTweetPadding(tweetIdx);
res = new PutOperation(client, SocialBenchmark.userTable,
tweet.getUser(), user, null);
this.get = false;
}
break;
case TWEET:
tweetMap.put(Utils.ID, this.tweetId);
// this.tags.add(0,Utils.getTagTweetID(this.tweetId));
res = new PutOperation(client, SocialBenchmark.tweetsTable,
tweetId, tweetMap, this.tags);
this.get = false;
break;
case FOLLOWERS:
/*
* if (!this.get) { res=new
* MultiGetOperation<String>(client,TwitterBenchmark
* .friendsTimeLineTable,this.followers); this.get=true; } else {
*/
this.setTweetToFriendsTimeLine();
res = new MultiPutOperation<String, String>(client,
SocialBenchmark.friendsTimeLineTable,
this.tweetFriendsTimeline);
this.finish = true;
// }
break;
}
res.addListener(this);
if (init)
res.setInit(true);
return res;
}
@Override
public boolean hasMoreDBOperations() {
return !finish;
}
@Override
public String toString() {
return "TweetOperation [tweet=" + tweet + ";tags:" + tags + "]";
}
public void setInit(boolean init) {
this.init = init;
}
public boolean isInit() {
return init;
}
@Override
public boolean isReadOnly() {
return false;
}
}