package qa.qcri.aidr.manager.service.impl; import java.net.URLEncoder; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.codehaus.jackson.map.ObjectMapper; import org.glassfish.jersey.jackson.JacksonFeature; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import qa.qcri.aidr.common.code.JacksonWrapper; import qa.qcri.aidr.common.values.UsageType; import qa.qcri.aidr.manager.dto.CollectionBriefInfo; import qa.qcri.aidr.manager.dto.CollectionDetailsInfo; import qa.qcri.aidr.manager.dto.CollectionStatsInfo; import qa.qcri.aidr.manager.dto.CollectionSummaryInfo; import qa.qcri.aidr.manager.dto.CollectionUpdateInfo; import qa.qcri.aidr.manager.dto.FetcheResponseDTO; import qa.qcri.aidr.manager.dto.FetcherRequestDTO; import qa.qcri.aidr.manager.dto.PingResponse; import qa.qcri.aidr.manager.exception.AidrException; import qa.qcri.aidr.manager.persistence.entities.Collection; import qa.qcri.aidr.manager.persistence.entities.CollectionLog; import qa.qcri.aidr.manager.persistence.entities.CrisisType; import qa.qcri.aidr.manager.persistence.entities.UserAccount; import qa.qcri.aidr.manager.persistence.entities.UserConnection; import qa.qcri.aidr.manager.repository.AuthenticateTokenRepository; import qa.qcri.aidr.manager.repository.CollectionLogRepository; import qa.qcri.aidr.manager.repository.CollectionRepository; import qa.qcri.aidr.manager.repository.UserConnectionRepository; import qa.qcri.aidr.manager.service.CollectionCollaboratorService; import qa.qcri.aidr.manager.service.CollectionLogService; import qa.qcri.aidr.manager.service.CollectionService; import qa.qcri.aidr.manager.service.CrisisTypeService; import qa.qcri.aidr.manager.service.TaggerService; import qa.qcri.aidr.manager.service.UserConnectionService; import qa.qcri.aidr.manager.service.WordDictionaryService; import qa.qcri.aidr.manager.util.CollectionStatus; import qa.qcri.aidr.manager.util.CollectionType; import qa.qcri.aidr.manager.util.SMS; import qa.qcri.aidr.manager.util.SocialSignInProvider; import twitter4j.ResponseList; import twitter4j.Twitter; import twitter4j.TwitterFactory; import twitter4j.User; import twitter4j.auth.AccessToken; @Service("collectionService") public class CollectionServiceImpl implements CollectionService { private final Logger logger = Logger.getLogger(getClass()); @Autowired private CollectionRepository collectionRepository; @Autowired private CollectionLogRepository collectionLogRepository; @Autowired private UserConnectionRepository userConnectionRepository; @Autowired private UserConnectionService userConnectionService; @Autowired private TaggerService taggerService; @Autowired private AuthenticateTokenRepository authenticateTokenRepository; @Autowired private CollectionCollaboratorService collaboratorService; @Autowired private CrisisTypeService crisisTypeService; @Autowired private WordDictionaryService wordService; @Value("${fetchMainUrl}") private String fetchMainUrl; @Value("${twitter.consumerKey}") private String consumerKey; @Value("${twitter.consumerSecret}") private String consumerSecret; @Value("${facebook.consumerKey}") private String facebookConsumerKey; @Value("${facebook.consumerSecret}") private String facebookConsumerSecret; private String accessTokenStr = null; private String accessTokenSecretStr = null; @Autowired private CollectionLogService collectionLogService; @Override @Transactional(readOnly=false) public void update(Collection collection) { collectionRepository.update(collection); } @Override @Transactional(readOnly=false) public boolean updateCollection(CollectionUpdateInfo collectionUpdateInfo, Long userId) { String filteredTrack = ""; try { Collection collection = findByCode(collectionUpdateInfo.getCode()); if(!collection.getName().equals(collectionUpdateInfo.getName())) { if(!existName(collectionUpdateInfo.getName())) { collection.setName(collectionUpdateInfo.getName()); } else { return false; } } // if collection exists with same name collection.setProvider(CollectionType.valueOf(collectionUpdateInfo.getProvider())); collection.setFollow(collectionUpdateInfo.getFollow()); collection.setFetchInterval(collectionUpdateInfo.getFetchInterval()); collection.setFetchFrom(collectionUpdateInfo.getFetchFrom()); filteredTrack = collectionUpdateInfo.getTrack(); if(!StringUtils.isEmpty(filteredTrack)) { filteredTrack = getFilteredTrack(filteredTrack); if(StringUtils.isEmpty(filteredTrack)) { return false; } } collection.setTrack(filteredTrack); collection.setGeo(collectionUpdateInfo.getGeo()); collection.setGeoR(collectionUpdateInfo.getGeoR()); collection.setDurationHours(Integer.parseInt(collectionUpdateInfo.getDurationHours())); collection.setLangFilters(collectionUpdateInfo.getLangFilters()); Long crisisTypeId = Long.parseLong(collectionUpdateInfo.getCrisisType()); CrisisType crisisType = crisisTypeService.getById(crisisTypeId); if(crisisType!=null){ collection.setCrisisType(crisisType); } else{ logger.error("Crisis Type Id: "+crisisTypeId +" does not exist. Can't update the collection : " + collectionUpdateInfo.getCode()); return false; } if (CollectionType.SMS.equals(collection.getProvider())) { collection.setTrack(null); collection.setLangFilters(null); collection.setGeo(null); collection.setGeoR(null); collection.setFollow(null); } if(collection.getProvider() == CollectionType.Twitter){ collection.setFollow(this.getFollowTwitterIDs(collectionUpdateInfo.getFollow(), collection.getOwner().getUserName())); } collectionRepository.update(collection); // first make an entry in log if collection is running if (CollectionStatus.RUNNING_WARNING.equals(collection.getStatus()) || CollectionStatus.RUNNING.equals(collection.getStatus())) { this.stop(collection.getId(), userId); this.startFetcher(this.prepareFetcherRequest(collection), collection); } return true; } catch (Exception e) { logger.error("Unable to update the collection : " + collectionUpdateInfo.getCode(), e); return false; } } @Override @Transactional(readOnly = false) public void delete(Collection collection) throws Exception { collectionRepository.delete(collection); } @Override @Transactional public Collection create(CollectionDetailsInfo collectionDetailsInfo, UserAccount user) throws Exception { String filteredTrack = collectionDetailsInfo.getTrack(); if(!StringUtils.isEmpty(filteredTrack)) { filteredTrack = getFilteredTrack(filteredTrack); if(StringUtils.isEmpty(filteredTrack)) { return null; } } Collection collection = adaptCollectionDetailsInfoToCollection(collectionDetailsInfo, user); collection.setTrack(filteredTrack); collection.setUsageType(UsageType.Production); try { collectionRepository.save(collection); collaboratorService.addCollaboratorToCollection(collectionDetailsInfo.getCode(), user.getId()); return collection; } catch (Exception e) { logger.error("Error in creating collection.", e); return null; } } // this method is common to get collection and should not filter by status @Override @Transactional(readOnly = true) public Collection findById(Long id) throws Exception { return collectionRepository.findById(id); } // this method is common to get collection and should not filter by status @Override @Transactional(readOnly = true) public Collection findByCode(String code) throws Exception { return collectionRepository.findByCode(code); } @Override @Transactional(readOnly = true) public Collection findTrashedById(Long id) throws Exception { Collection temp = collectionRepository.findById(id); if (temp.getStatus().equals(CollectionStatus.TRASHED)) { return temp; } return null; } @Override @Transactional(readOnly = true) public Collection findTrashedByCode(String code) throws Exception { Collection temp = collectionRepository.findByCode(code); if (temp.getStatus().equals(CollectionStatus.TRASHED)) { return temp; } return null; } @Override @Transactional(readOnly = true) public List<Collection> findAll(Integer start, Integer limit, UserAccount user, boolean onlyTrashed) throws Exception { return collectionRepository.getPaginatedData(start, limit, user, onlyTrashed); } @Override @Transactional(readOnly = true) public List<Collection> findAllForPublic(Integer start, Integer limit, Enum statusValue) throws Exception { return collectionRepository.getPaginatedDataForPublic(start, limit, statusValue); } @Override @Transactional(readOnly = true) public List<Collection> searchByName(String query, Long userId) throws Exception { return collectionRepository.searchByName(query, userId); } @Override @Transactional(readOnly = true) public Boolean exist(String code) throws Exception { return collectionRepository.exist(code); } @Override @Transactional(readOnly = true) public Boolean existName(String name) throws Exception { return collectionRepository.existName(name); } @Override @Transactional(readOnly = true) public Collection getRunningCollectionStatusByUser(Long userId) throws Exception { return collectionRepository.getRunningCollectionStatusByUser(userId); } @Override @Transactional(readOnly = false) public Collection updateAndGetRunningCollectionStatusByUser(Long userId) throws Exception { Collection collection = collectionRepository.getRunningCollectionStatusByUser(userId); if (collection != null){ logger.info("User with ID: '" + userId + "' has a running collection with code: '" + collection.getCode()); return statusByCollection(collection, userId); } else { //logger.info("User with ID: '" + userId + "' don't have any running collections. Nothing to update." ); // If there is no running collection there is still can be collection with status 'Initializing'. // This happens because we update collection information from fetcher before collection was started. // So we need to update from Fetcher this kind of collections as well. collection = collectionRepository.getInitializingCollectionStatusByUser(userId); if (collection != null) { return statusByCollection(collection, userId); } } return null; } @Override @Transactional(readOnly = false) public Collection start(Long collectionId) throws Exception { // We are going to start new collection. Lets stop collection which is running for owner of the new collection. Collection dbCollection = collectionRepository.findById(collectionId); Long userId = dbCollection.getOwner().getId(); Collection alreadyRunningCollection = collectionRepository.getRunningCollectionStatusByUser(userId); if (alreadyRunningCollection != null) { this.stop(alreadyRunningCollection.getId(), userId); } return startFetcher(prepareFetcherRequest(dbCollection), dbCollection); } @Override @Transactional(readOnly = true) public FetcherRequestDTO prepareFetcherRequest(Collection dbCollection) { FetcherRequestDTO dto = new FetcherRequestDTO(); UserConnection userconnection = userConnectionService.fetchByCombinedUserName(dbCollection.getOwner().getUserName()); dto.setAccessToken(userconnection.getAccessToken()); dto.setAccessTokenSecret(userconnection.getSecret()); dto.setCollectionName(dbCollection.getName()); dto.setCollectionCode(dbCollection.getCode()); if(dbCollection.getProvider() == CollectionType.Facebook){ dto.setToFollow(dbCollection.getFollow()); }else{ dto.setToFollow(getFollowTwitterIDs(dbCollection.getFollow(), dbCollection.getOwner().getUserName())); } dto.setToTrack(dbCollection.getTrack()); dto.setGeoLocation(dbCollection.getGeo()); dto.setGeoR(dbCollection.getGeoR()); dto.setLanguageFilter(dbCollection.getLangFilters()); dto.setSaveMediaEnabled(dbCollection.isSaveMediaEnabled()); dto.setFetchInterval(dbCollection.getFetchInterval()); dto.setProvider(dbCollection.getProvider().toString()); dto.setFetchInterval(dbCollection.getFetchInterval()); dto.setFetchFrom(dbCollection.getFetchFrom()); dto.setLastExecutionTime(dbCollection.getLastExecutionTime()); // Added by koushik accessTokenStr = dto.getAccessToken(); accessTokenSecretStr = dto.getAccessTokenSecret(); return dto; } @Override @Transactional(readOnly = false) public Collection stop(Long collectionId, Long userId) throws Exception { Collection collection = collectionRepository.findById(collectionId); // Follwoing 2 lines added by koushik for downloadCount bug Collection c = this.statusByCollection(collection, userId); collection.setCount(c.getCount()); Collection updateCollection = stopAidrFetcher(collection, userId); CollectionLog collectionLog = new CollectionLog(collection); collectionLog.setUpdatedBy(userId); collectionLogRepository.save(collectionLog); return updateCollection; } //MEGHNA: method for stopping a collection on FATAL_ERROR //separate method from stop needed to prevent looping in //updateStatusCollection() method public Collection stopFatalError(Long collectionId, Long userId) throws Exception { Collection collection = collectionRepository.findById(collectionId); //collection = collectionRepository.stop(collection.getId()); Collection updateCollection = stopAidrFetcher(collection, userId); CollectionLog collectionLog = new CollectionLog(collection); collectionLogRepository.save(collectionLog); return updateCollection; } @Override @Transactional(readOnly = false) public Collection startFetcher(FetcherRequestDTO fetcherRequest, Collection collection) { try { /** * Rest call to Fetcher */ Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); if (CollectionType.Twitter.equals(collection.getProvider()) || CollectionType.Facebook.equals(collection.getProvider())) { WebTarget webResource = client.target(fetchMainUrl + "/" +collection.getProvider().toString().toLowerCase() + "/start"); ObjectMapper objectMapper = JacksonWrapper.getObjectMapper(); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON) .post(Entity.json(objectMapper.writeValueAsString(fetcherRequest)), Response.class); //logger.info("ObjectMapper: " + objectMapper.writeValueAsString(fetcherRequest)); String jsonString = clientResponse.readEntity(String.class); JSONParser parser = new JSONParser(); JSONObject jsonResponse = (JSONObject) parser.parse(jsonString); //logger.info("NEW STRING: " + jsonResponse); FetcheResponseDTO response = objectMapper.readValue(jsonResponse.get("entity").toString(), FetcheResponseDTO.class); logger.info("start Response from fetchMain " + objectMapper.writeValueAsString(response)); collection.setStatus(CollectionStatus.getByStatus(response.getStatusCode())); } else if (CollectionType.SMS.equals(collection.getProvider())) { WebTarget webResource = client.target(fetchMainUrl + "/sms/start?collection_code=" + URLEncoder.encode(collection.getCode(), "UTF-8")); Response response = webResource.request(MediaType.APPLICATION_JSON).get(); if (response.getStatus() == 200) collection.setStatus(CollectionStatus.INITIALIZING); } /** * Update Status To database */ collectionRepository.update(collection); return collection; } catch (Exception e) { logger.error("Error while starting Remote FetchMain Collection", e); } return null; } @Override public boolean pingCollector() throws AidrException { try { Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); WebTarget webResource = client.target(fetchMainUrl + "/manage/ping"); ObjectMapper objectMapper = JacksonWrapper.getObjectMapper(); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonResponse = clientResponse.readEntity(String.class); PingResponse pingResponse = objectMapper.readValue(jsonResponse, PingResponse.class); if (pingResponse != null && "RUNNING".equals(pingResponse.getCurrentStatus())) { return true; } else { return false; } } catch (Exception e) { throw new AidrException("Error while pinging the collector.", e); } } @Override @Transactional(readOnly = false) public Collection stopAidrFetcher(Collection collection, Long userId) { try { /** * Rest call to Fetcher */ Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); String path = ""; if(CollectionType.SMS.equals(collection.getProvider())) { path = "/sms/stop?collection_code="; } else { path = "/" + collection.getProvider().toString().toLowerCase() + "/stop?id="; } WebTarget webResource = client.target(fetchMainUrl + path + URLEncoder.encode(collection.getCode(), "UTF-8")); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonString = clientResponse.readEntity(String.class); JSONParser parser = new JSONParser(); JSONObject jsonResponse = (JSONObject) parser.parse(jsonString); collection = updateStatusCollection(jsonResponse.get("entity").toString(), collection, userId); /** * Change Database Status */ return this.collectionRepository.stop(collection.getId()); } catch (Exception e) { logger.error("Error while stopping Remote FetchMain Collection", e); } return null; } private Collection updateStatusCollection(String jsonResponse, Collection collection, Long accountId) throws Exception { ObjectMapper objectMapper = JacksonWrapper.getObjectMapper(); FetcheResponseDTO response = objectMapper.readValue(jsonResponse, FetcheResponseDTO.class); if (response != null) { //MEGHNA: moved setting collection count to top of the method //to avoid individual status blocks setting collection count below if (response.getCollectionCount() != null && !response.getCollectionCount().equals(collection.getCount())) { collection.setCount(response.getCollectionCount()); String lastDocument = response.getLastDocument(); collection.setLastExecutionTime(response.getLastExecutionTime()); if (lastDocument != null) collection.setLastDocument(lastDocument); collectionRepository.update(collection); } collection.setSourceOutage(response.isSourceOutage()); if (!CollectionStatus.getByStatus(response.getStatusCode()).equals(collection.getStatus())) { CollectionStatus prevStatus = collection.getStatus(); collection.setStatus(CollectionStatus.getByStatus(response.getStatusCode())); switch(CollectionStatus.getByStatus(response.getStatusCode())) { case NOT_FOUND: //case STOPPED: collection.setStatus(CollectionStatus.NOT_RUNNING); //Add collectionCount in collectionLog if it was not recorded. if (collection.getStartDate() != null && ((collection.getEndDate() != null && collection.getStartDate().after(collection.getEndDate())) || collection.getEndDate() == null)) { if(collectionLogRepository.countLogsStartedInInterval(collection.getId(), collection.getStartDate(), new Date())==0){ CollectionLog collectionLog = new CollectionLog(collection); collectionLog.setEndDate(new Date()); collectionLog.setUpdatedBy(accountId); collectionLogRepository.save(collectionLog); } } case RUNNING_WARNING: if(prevStatus == CollectionStatus.INITIALIZING) { collection = collectionRepository.start(collection.getId()); break; } case WARNING: collectionRepository.update(collection); break; case RUNNING: collection = collectionRepository.start(collection.getId()); break; case FATAL_ERROR: //collection = collectionRepository.stop(collection.getId()); logger.warn("Fatal error, stopping collection " + collection.getId()); if(prevStatus != CollectionStatus.FATAL_ERROR || prevStatus != CollectionStatus.NOT_RUNNING || prevStatus != CollectionStatus.STOPPED) this.stopFatalError(collection.getId(), accountId); break; case EXCEPTION: logger.warn("Rejected Thread Execution Exception, restarting collection " + collection.getId()); if(prevStatus!=CollectionStatus.EXCEPTION){ this.stopFatalError(collection.getId(), accountId); this.start(collection.getId()); } break; default: break; } } } return collection; } //@SuppressWarnings("deprecation") @Transactional @Override public Collection statusById(Long id, Long userId) throws Exception { Collection collection = this.findById(id); return statusByCollection(collection, userId); } //@SuppressWarnings("deprecation") @Transactional @Override public Collection statusByCollection(Collection collection, Long accountId) throws Exception { if (collection != null) { try { /** * Make a call to fetcher Status Rest API */ Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); String path = ""; if (CollectionType.Twitter.equals(collection.getProvider()) || CollectionType.Facebook.equals(collection.getProvider())) { path = "/" +collection.getProvider().toString().toLowerCase() + "/status?id="; } else if(CollectionType.SMS.equals(collection.getProvider())) { path = "/sms/status?collection_code="; } WebTarget webResource = client.target(fetchMainUrl + path + URLEncoder.encode(collection.getCode(), "UTF-8")); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonString = clientResponse.readEntity(String.class); JSONParser parser = new JSONParser(); JSONObject jsonResponse = (JSONObject) parser.parse(jsonString); collection = updateStatusCollection(jsonResponse.get("entity").toString(), collection, accountId); return collection; } catch (Exception e) { String msg = "Error while getting status for collection from Remote FetchMain Collection"; logger.error(msg, e); throw new Exception(msg); } } return null; } @Override @Transactional(readOnly = true) public List<Collection> getRunningCollections() throws Exception { return collectionRepository.getRunningCollections(); } @Override @Transactional(readOnly = true) public List<Collection> getRunningCollections(Integer start, Integer limit, String terms, String sortColumn, String sortDirection) throws Exception { return collectionRepository.getRunningCollections(start, limit, terms, sortColumn, sortDirection); } @Override @Transactional(readOnly = true) public Long getRunningCollectionsCount(String terms) throws Exception { return collectionRepository.getRunningCollectionsCount(terms); } @Override public Long getRunningCollectionsCount() { return collectionRepository.getRunningCollectionsCount(""); } @Override @Transactional(readOnly = true) public Long getTotalCollectionsCount() { return collectionRepository.getTotalCollectionsCount(); } @Override @Transactional(readOnly = true) public List<Collection> getStoppedCollections(Integer start, Integer limit, String terms, String sortColumn, String sortDirection) throws Exception { return collectionRepository.getStoppedCollections(start, limit, terms, sortColumn, sortDirection); } @Override @Transactional(readOnly = true) public Long getStoppedCollectionsCount(String terms) throws Exception { return collectionRepository.getStoppedCollectionsCount(terms); } @Override @Transactional(readOnly = true) public Integer getCollectionsCount(UserAccount user, boolean onlyTrashed) throws Exception { return collectionRepository.getCollectionsCount(user, onlyTrashed); } @Override @Transactional(readOnly = true) public Integer getPublicCollectionsCount(Enum statusValue) throws Exception { return collectionRepository.getPublicCollectionsCount(statusValue); } @Override @Transactional(readOnly = true) public Boolean isValidToken(String token) throws Exception { return authenticateTokenRepository.isAuthorized(token); } @Override @Transactional(readOnly = true) public List<Collection> geAllCollectionByUser(Long userId) throws Exception{ return collectionRepository.getAllCollectionByUser(userId); } @Override @Transactional(readOnly = true) public String getFollowTwitterIDs(String followList, String userName) { if (followList != null && !followList.isEmpty()) { List<String> userList = Arrays.asList(followList.split(",")); if (null == accessTokenStr || null == accessTokenSecretStr) { UserConnection userConnection = userConnectionService.fetchByCombinedUserName(userName); accessTokenStr = userConnection.getAccessToken(); accessTokenSecretStr = userConnection.getSecret(); } String[] userNameList = null; long[] userIdList = null; if (userList != null) { try { userNameList = new String[userList.size()]; userIdList = new long[userList.size()]; int i = 0; int j = 0; logger.info("Received string: " + followList + ", Split follow string: " + userList); for (String user: userList) { //logger.info("Looking at follow data: " + user); if (StringUtils.isNumeric(user.trim())) { try { userIdList[j] = Long.parseLong(user.trim()); //logger.info("Going to fetch twitter userData for the following twitterID: " + userIdList[j]); ++j; } catch (Exception ex) { logger.error("Exception in parsing string to number: ", ex); } } else { userNameList[i] = user.trim(); //logger.info("Going to fetch twitter userData for the following screen name: " + userNameList[i]); ++i; } } userNameList = ArrayUtils.subarray(userNameList, 0, i); userIdList = ArrayUtils.subarray(userIdList, 0, j); } catch (Exception e) { logger.error("Exception while getting follow twitter Ids",e); } } List<User> dataList = new ArrayList<User>(); if (userNameList != null && userNameList.length > 0) { dataList.addAll(getUserDataFromScreenName(userNameList, userName)); } if (userIdList != null && userIdList.length > 0) { dataList.addAll(getUserDataFromTwitterID(userIdList, userName)); } if (!dataList.isEmpty()) { StringBuffer followIDs = new StringBuffer(); for (User u: dataList) { followIDs.append(u.getId()).append(","); } followIDs.deleteCharAt(followIDs.lastIndexOf(",")); //logger.info("Created follow twitterID list: " + followIDs.toString()); return followIDs.toString(); } else { return null; } } return null; } @Override @Transactional(readOnly = true) public String getFollowTwitterScreenNames(String followList, String userName) { if (followList != null && !followList.isEmpty()) { List<String> userList = Arrays.asList(followList.split(",")); if (null == accessTokenStr || null == accessTokenSecretStr) { UserConnection userConnection = userConnectionService.fetchByCombinedUserName(userName); accessTokenStr = userConnection.getAccessToken(); accessTokenSecretStr = userConnection.getSecret(); } long[] userIdList = null; if (userList != null) { try { userIdList = new long[userList.size()]; int j = 0; logger.info("Received string: " + followList + ", Split follow string: " + userList); for (String user: userList) { //logger.info("Looking at follow data: " + user); if (StringUtils.isNumeric(user.trim())) { try { userIdList[j] = Long.parseLong(user.trim()); //logger.info("Going to fetch twitter userData for the following twitterID: " + userIdList[j]); ++j; } catch (Exception ex) { logger.error("Exception in parsing string to number: ", ex); } } } userIdList = ArrayUtils.subarray(userIdList, 0, j); } catch (Exception e) { e.printStackTrace(); } } List<User> dataList = new ArrayList<User>(); if (userIdList != null && userIdList.length > 0) { dataList.addAll(getUserDataFromTwitterID(userIdList, userName)); } if (!dataList.isEmpty()) { StringBuffer followScreenNames = new StringBuffer(); for (User user: dataList) { followScreenNames.append(user.getScreenName()).append(","); } followScreenNames.deleteCharAt(followScreenNames.lastIndexOf(",")); //logger.info("Created follow twitterID list: " + followScreenNames.toString()); return followScreenNames.toString(); } else { return null; } } return null; } @Override @Transactional(readOnly = false) public boolean enableClassifier(String code, UserAccount currentUser) { try { Collection collection = findByCode(code); if(collection != null) { collection.setClassifierEnabled(Boolean.TRUE); collection.setClassifierEnabledBy(currentUser); this.update(collection); } return Boolean.TRUE; } catch (Exception e) { logger.error("Error in enabling classifier for code : " + code, e); return Boolean.FALSE; } } @Override @Transactional(readOnly = true) public Boolean isValidAPIKey(String code, String apiKey) throws Exception { Collection collection = findByCode(code); if(collection.getOwner().getApiKey().equals(apiKey)){ return true; } return false; } @Override public Boolean pushSMS(String collectionCode, SMS sms) { try { /** * Rest call to Fetcher */ Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); WebTarget webResource = client.target(fetchMainUrl + "/sms/endpoint/receive/"+ URLEncoder.encode(collectionCode, "UTF-8")); ObjectMapper objectMapper = JacksonWrapper.getObjectMapper(); Response response = webResource.request(MediaType.APPLICATION_JSON) .post(Entity.json(objectMapper.writeValueAsString(sms)), Response.class); if(response.getStatus()!=200){ return false; } else{ return true; } } catch (Exception e) { logger.error("Exception while pushing sms", e); return false; } } @Override public List<CollectionSummaryInfo> getAllCollectionDataByUsage(UsageType usage) { /*List<CollectionSummaryInfo> collectionSummaryInfos = new ArrayList<CollectionSummaryInfo>(); List<Collection> collections = collectionRepository.getAllCollectionsByUsage(usage); if(collections != null) { collectionSummaryInfos = adaptCollectionListToCollectionSummaryInfoList(collections); }*/ List<CollectionSummaryInfo> collectionSummaryInfos = collectionRepository.getAllCollectionForAidrData(); return collectionSummaryInfos; } @Override public List<CollectionBriefInfo> getMicromappersFilteredCollections( boolean micromappersEnabled) { List<Collection> collections = collectionRepository.findMicromappersFilteredCollections(micromappersEnabled); List<CollectionBriefInfo> briefInfos = new ArrayList<CollectionBriefInfo>(); if(collections != null && collections.size() > 0) { briefInfos = adaptCollectionListToCollectionBriefInfoList(collections); } return briefInfos; } @Override public Long getRunningCollectionDataCount() { Long collectionCountSinceLastRestart = 0L; Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); try { WebTarget webResource = client.target(fetchMainUrl + "/manage/count"); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonString = clientResponse.readEntity(String.class); JSONParser parser = new JSONParser(); JSONObject jsonResponse = (JSONObject) parser.parse(jsonString); collectionCountSinceLastRestart = (Long) jsonResponse.get("count"); } catch (Exception e) { logger.warn("Error while fetching count", e); } return collectionCountSinceLastRestart; } @Override public CollectionStatsInfo getCollectionStatistics() { Long runningCollectionsCount = this.getRunningCollectionsCount(); Long totalCollectionCount = this.getTotalCollectionsCount(); Long totalDataCount = collectionLogService.countTotalTweets() + this.getRunningCollectionDataCount(); CollectionStatsInfo collectionStatsInfo = new CollectionStatsInfo(); collectionStatsInfo.setTotalCollectionsCount(totalCollectionCount); collectionStatsInfo.setRunningCollectionCount(runningCollectionsCount); collectionStatsInfo.setTotalDataCount(totalDataCount); collectionStatsInfo.setOfflineCollectionCount(totalCollectionCount - runningCollectionsCount); return collectionStatsInfo; } @Override public List<String> fetchEligibleFacebookCollectionsToReRun() { List<String> codes = collectionRepository.getEligibleFacebookCollectionsToReRun(); return codes; } @Override public void rerunFacebookCollection(String code) { Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); WebTarget webResource = client.target(fetchMainUrl + "/facebook/rerun?code=" + code); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); Map<String, String> result = clientResponse.readEntity(Map.class); } private List<User> getUserDataFromScreenName(String[] userNameList, String userName) { if (userNameList != null) { try { Twitter twitter = new TwitterFactory().getInstance(); twitter.setOAuthConsumer(consumerKey, consumerSecret); AccessToken accessToken = new AccessToken(accessTokenStr, accessTokenSecretStr); twitter.setOAuthAccessToken(accessToken); ResponseList<User> list = twitter.lookupUsers(userNameList); logger.info("Successfully looked up in Twitter by screen name, size of list: " + list.size()); return (list != null ? list : new ArrayList<User>()); } catch (Exception e) { logger.error("Exception while getting user Data from screen Name for user: "+userName,e); } } return new ArrayList<User>(); } private List<User> getUserDataFromTwitterID(long[] userIdList, String userName) { if (userIdList != null) { try { Twitter twitter = new TwitterFactory().getInstance(); twitter.setOAuthConsumer(consumerKey, consumerSecret); AccessToken accessToken = new AccessToken(accessTokenStr, accessTokenSecretStr); twitter.setOAuthAccessToken(accessToken); ResponseList<User> list = twitter.lookupUsers(userIdList); logger.info("Successfully looked up in Twitter by ID, size of list: " + list.size()); return (list != null ? list : new ArrayList<User>()); } catch (Exception e) { logger.error("Exception while getting user Data from TwitterId for user: "+userName,e); } } return new ArrayList<User>(); } private Collection adaptCollectionDetailsInfoToCollection(CollectionDetailsInfo collectionInfo, UserAccount user) { Collection collection = new Collection(); collection.setDurationHours(collectionInfo.getDurationHours()); collection.setCode(collectionInfo.getCode()); collection.setName(collectionInfo.getName()); collection.setClassifierEnabled(false); collection.setProvider(CollectionType.valueOf(collectionInfo.getProvider())); collection.setOwner(user); collection.setStatus(CollectionStatus.NOT_RUNNING); collection.setPubliclyListed(true); // TODO: change default behavior to user choice collection.setGeoR(collectionInfo.getGeoR()); collection.setGeo(collectionInfo.getGeo()); collection.setTrack(collectionInfo.getTrack()); collection.setCrisisType(crisisTypeService.getById(collectionInfo.getCrisisType())); collection.setFollow(collectionInfo.getFollow()); collection.setLangFilters(collectionInfo.getLangFilters()); collection.setMicromappersEnabled(Boolean.FALSE); collection.setProvider(CollectionType.valueOf(collectionInfo.getProvider())); collection.setPurpose(collectionInfo.getPurpose()); collection.setFetchInterval(collectionInfo.getFetchInterval()); collection.setFetchFrom(collectionInfo.getFetchFrom()); if(CollectionType.SMS.equals(collectionInfo.getProvider())) { collection.setTrack(null); collection.setLangFilters(null); collection.setGeo(null); collection.setFollow(null); } Timestamp now = new Timestamp(System.currentTimeMillis()); collection.setCreatedAt(now); collection.setUpdatedAt(now); return collection; } private List<CollectionSummaryInfo> adaptCollectionListToCollectionSummaryInfoList(List<Collection> collections) { List<CollectionSummaryInfo> collectionSummaryInfos = new ArrayList<CollectionSummaryInfo>(); for(Collection collection : collections) { collectionSummaryInfos.add(adaptCollectionToCollectionSummaryInfo(collection)); } return collectionSummaryInfos; } private CollectionSummaryInfo adaptCollectionToCollectionSummaryInfo(Collection collection) { CollectionSummaryInfo summaryInfo = new CollectionSummaryInfo(); summaryInfo.setCode(collection.getCode()); summaryInfo.setName(collection.getName()); summaryInfo.setCurator(collection.getOwner().getUserName()); summaryInfo.setStartDate(collection.getStartDate()); summaryInfo.setEndDate(collection.getEndDate()); summaryInfo.setCollectionCreationDate(collection.getCreatedAt()); // TODO to fetch from collection log try { summaryInfo.setTotalCount(collectionLogService.countTotalDownloadedItemsForCollection(collection.getId())); } catch (Exception e) { logger.warn("Error in fetch count from collection log.", e); summaryInfo.setTotalCount(collection.getCount()); } summaryInfo.setStatus(collection.getStatus().getStatus()); // TODO summaryInfo.setCreatedAt(collection.getCreatedAt()); summaryInfo.setLanguage(collection.getLangFilters()); summaryInfo.setKeywords(collection.getTrack()); summaryInfo.setGeo(collection.getGeo()); summaryInfo.setLabelCount(taggerService.getLabelCount(collection.getId())); summaryInfo.setPubliclyListed(collection.isPubliclyListed()); summaryInfo.setProvider(collection.getProvider().toString()); return summaryInfo; } private List<CollectionBriefInfo> adaptCollectionListToCollectionBriefInfoList(List<Collection> collections) { List<CollectionBriefInfo> collectionBriefInfos = new ArrayList<CollectionBriefInfo>(); for(Collection collection : collections) { collectionBriefInfos.add(adaptCollectionToCollectionBriefInfo(collection)); } return collectionBriefInfos; } private CollectionBriefInfo adaptCollectionToCollectionBriefInfo(Collection collection) { CollectionBriefInfo briefInfo = new CollectionBriefInfo(); briefInfo.setCollectionId(collection.getId()); briefInfo.setCollectionCode(collection.getCode()); briefInfo.setCollectionName(collection.getName()); briefInfo.setMicromappersEnabled(collection.isMicromappersEnabled()); briefInfo.setProvider(collection.getProvider().name()); return briefInfo; } private String getFilteredTrack(String trackToFilter) { String filteredTrack = ""; //trackToFilter = trackToFilter.replaceAll(", ", ","); String[] trackArray = trackToFilter.split(",\\s*"); List<String> toFilter = new ArrayList<String>(); toFilter.addAll(Arrays.asList(trackArray)); List<String> stopWordList = wordService.fetchAllStopWords(); toFilter.removeAll(stopWordList); if(toFilter != null && !toFilter.isEmpty()) { trackArray = toFilter.toArray(new String[] {}); filteredTrack = Arrays.toString(trackArray); filteredTrack = filteredTrack.substring(1, filteredTrack.length()-1); } return filteredTrack.trim(); } @Override public int getRunningCollectionsCountFromCollector() { int runningCollections = 0; try { Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); WebTarget webResource = client.target(fetchMainUrl + "/manage/ping"); ObjectMapper objectMapper = JacksonWrapper.getObjectMapper(); Response clientResponse = webResource.request(MediaType.APPLICATION_JSON).get(); String jsonResponse = clientResponse.readEntity(String.class); PingResponse pingResponse = objectMapper.readValue(jsonResponse, PingResponse.class); if (pingResponse != null && "RUNNING".equals(pingResponse.getCurrentStatus())) { runningCollections = Integer.parseInt(pingResponse.getRunningCollectionsCount()); } } catch (Exception e) { logger.error("Collector is not reachable"); } return runningCollections; } @Override public List<Collection> getUnexpectedlyStoppedCollections(Date today) { return collectionRepository.getUnexpectedlyStoppedCollections(today); } @Override public JSONArray searchFacebookProfiles(String keyword, Integer offset, Integer limit, UserAccount userEntity){ UserConnection userConnection = userConnectionService.fetchByCombinedUserName(userEntity.getUserName()); userConnection.getAccessToken(); try{ Client client = ClientBuilder.newBuilder().register(JacksonFeature.class).build(); WebTarget webResource = client.target(fetchMainUrl + "/" +SocialSignInProvider.FACEBOOK + "/searchProfiles" + "?offset=" + offset + "&limit=" + limit + "&keyword=" + URLEncoder.encode(keyword, "UTF-8")); ObjectMapper objectMapper = JacksonWrapper.getObjectMapper(); Response clientResponse = webResource.request( MediaType.APPLICATION_JSON).post( Entity.json(userConnection.getAccessToken()), Response.class); String jsonString = clientResponse.readEntity(String.class); JSONParser parser = new JSONParser(); JSONObject jsonResponse = (JSONObject) parser.parse(jsonString); JSONArray response = objectMapper.readValue(jsonResponse.get("entity").toString(), JSONArray.class); return response; }catch(Exception e){ logger.error("Exception while searching facebok profiles",e); } return null; } }