@Override public void prepare(Object configurationObject) { mapper = StreamsJacksonMapper.getInstance(); uriBuilder = new URIBuilder() .setScheme(this.configuration.getProtocol()) .setHost(this.configuration.getHostname()) .setPath(this.configuration.getResourcePath()); if (!Strings.isNullOrEmpty(configuration.getAccessToken())) uriBuilder = uriBuilder.addParameter("access_token", configuration.getAccessToken()); if (!Strings.isNullOrEmpty(configuration.getUsername()) && !Strings.isNullOrEmpty(configuration.getPassword())) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(configuration.getUsername()); stringBuilder.append(":"); stringBuilder.append(configuration.getPassword()); String string = stringBuilder.toString(); authHeader = Base64.encodeBase64String(string.getBytes()); } httpclient = HttpClients.createDefault(); }
public class FacebookUserstreamProvider implements StreamsProvider, Serializable { public static final String STREAMS_ID = "FacebookUserstreamProvider"; private static final Logger LOGGER = LoggerFactory.getLogger(FacebookUserstreamProvider.class); private static final ObjectMapper mapper = StreamsJacksonMapper.getInstance(); private static final String ALL_PERMISSIONS = "read_stream"; private FacebookUserstreamConfiguration configuration; private Class klass; protected final ReadWriteLock lock = new ReentrantReadWriteLock(); protected volatile Queue<StreamsDatum> providerQueue = new LinkedBlockingQueue<StreamsDatum>(); public FacebookUserstreamConfiguration getConfig() { return configuration; } public void setConfig(FacebookUserstreamConfiguration config) { this.configuration = config; } protected ListeningExecutorService executor; protected DateTime start; protected DateTime end; protected final AtomicBoolean running = new AtomicBoolean(); private DatumStatusCounter countersCurrent = new DatumStatusCounter(); private DatumStatusCounter countersTotal = new DatumStatusCounter(); protected Facebook client; private static ExecutorService newFixedThreadPoolWithQueueSize(int nThreads, int queueSize) { return new ThreadPoolExecutor( nThreads, nThreads, 5000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(queueSize, true), new ThreadPoolExecutor.CallerRunsPolicy()); } public FacebookUserstreamProvider() { Config config = StreamsConfigurator.config.getConfig("facebook"); FacebookUserInformationConfiguration facebookUserInformationConfiguration; try { facebookUserInformationConfiguration = mapper.readValue( config.root().render(ConfigRenderOptions.concise()), FacebookUserInformationConfiguration.class); } catch (IOException e) { e.printStackTrace(); return; } } public FacebookUserstreamProvider(FacebookUserstreamConfiguration config) { this.configuration = config; } public FacebookUserstreamProvider(Class klass) { Config config = StreamsConfigurator.config.getConfig("facebook"); FacebookUserInformationConfiguration facebookUserInformationConfiguration; try { facebookUserInformationConfiguration = mapper.readValue( config.root().render(ConfigRenderOptions.concise()), FacebookUserInformationConfiguration.class); } catch (IOException e) { e.printStackTrace(); return; } this.klass = klass; } public FacebookUserstreamProvider(FacebookUserstreamConfiguration config, Class klass) { this.configuration = config; this.klass = klass; } public Queue<StreamsDatum> getProviderQueue() { return this.providerQueue; } @Override public void startStream() { client = getFacebookClient(); if (configuration.getInfo() != null && configuration.getInfo().size() > 0) { for (String id : configuration.getInfo()) { executor.submit(new FacebookFeedPollingTask(this, id)); } running.set(true); } else { try { String id = client.getMe().getId(); executor.submit(new FacebookFeedPollingTask(this, id)); running.set(true); } catch (FacebookException e) { LOGGER.error(e.getMessage()); running.set(false); } } } public StreamsResultSet readCurrent() { StreamsResultSet current; synchronized (FacebookUserstreamProvider.class) { current = new StreamsResultSet(Queues.newConcurrentLinkedQueue(providerQueue)); current.setCounter(new DatumStatusCounter()); current.getCounter().add(countersCurrent); countersTotal.add(countersCurrent); countersCurrent = new DatumStatusCounter(); providerQueue.clear(); } return current; } public StreamsResultSet readNew(BigInteger sequence) { LOGGER.debug("{} readNew", STREAMS_ID); throw new NotImplementedException(); } public StreamsResultSet readRange(DateTime start, DateTime end) { LOGGER.debug("{} readRange", STREAMS_ID); this.start = start; this.end = end; readCurrent(); StreamsResultSet result = (StreamsResultSet) providerQueue.iterator(); return result; } @Override public boolean isRunning() { return running.get(); } void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(10, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(10, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } @Override public void prepare(Object o) { executor = MoreExecutors.listeningDecorator(newFixedThreadPoolWithQueueSize(5, 20)); Preconditions.checkNotNull(providerQueue); Preconditions.checkNotNull(this.klass); Preconditions.checkNotNull(configuration.getOauth().getAppId()); Preconditions.checkNotNull(configuration.getOauth().getAppSecret()); Preconditions.checkNotNull(configuration.getOauth().getUserAccessToken()); client = getFacebookClient(); if (configuration.getInfo() != null && configuration.getInfo().size() > 0) { List<String> ids = new ArrayList<String>(); List<String[]> idsBatches = new ArrayList<String[]>(); for (String s : configuration.getInfo()) { if (s != null) { ids.add(s); if (ids.size() >= 100) { // add the batch idsBatches.add(ids.toArray(new String[ids.size()])); // reset the Ids ids = new ArrayList<String>(); } } } } } protected Facebook getFacebookClient() { ConfigurationBuilder cb = new ConfigurationBuilder(); cb.setDebugEnabled(true) .setOAuthAppId(configuration.getOauth().getAppId()) .setOAuthAppSecret(configuration.getOauth().getAppSecret()) .setOAuthAccessToken(configuration.getOauth().getUserAccessToken()) .setOAuthPermissions(ALL_PERMISSIONS) .setJSONStoreEnabled(true); FacebookFactory ff = new FacebookFactory(cb.build()); Facebook facebook = ff.getInstance(); return facebook; } @Override public void cleanUp() { shutdownAndAwaitTermination(executor); } private class FacebookFeedPollingTask implements Runnable { FacebookUserstreamProvider provider; Facebook client; String id; private Set<Post> priorPollResult = Sets.newHashSet(); public FacebookFeedPollingTask(FacebookUserstreamProvider facebookUserstreamProvider) { this.provider = facebookUserstreamProvider; } public FacebookFeedPollingTask( FacebookUserstreamProvider facebookUserstreamProvider, String id) { this.provider = facebookUserstreamProvider; this.client = provider.client; this.id = id; } @Override public void run() { while (provider.isRunning()) { ResponseList<Post> postResponseList; try { postResponseList = client.getFeed(id); Set<Post> update = Sets.newHashSet(postResponseList); Set<Post> repeats = Sets.intersection(priorPollResult, Sets.newHashSet(update)); Set<Post> entrySet = Sets.difference(update, repeats); LOGGER.debug( this.id + " response: " + update.size() + " previous: " + repeats.size() + " new: " + entrySet.size()); for (Post item : entrySet) { String json = DataObjectFactory.getRawJSON(item); org.apache.streams.facebook.Post post = mapper.readValue(json, org.apache.streams.facebook.Post.class); try { lock.readLock().lock(); ComponentUtils.offerUntilSuccess(new StreamsDatum(post), providerQueue); countersCurrent.incrementAttempt(); } finally { lock.readLock().unlock(); } } priorPollResult = update; } catch (Exception e) { e.printStackTrace(); } finally { try { Thread.sleep(configuration.getPollIntervalMillis()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } } }
/** * Test for * * @see {@link org.apache.streams.components.http.persist.SimpleHTTPPostPersistWriter} */ @RunWith(PowerMockRunner.class) @PrepareForTest({HttpClients.class, CloseableHttpResponse.class, CloseableHttpResponse.class}) public class SimpleHTTPPostPersistWriterTest { private ObjectMapper mapper = StreamsJacksonMapper.getInstance(); /** test port. */ private static final int PORT = 18080; /** test hosts. */ private static final String HOSTNAME = "localhost"; /** test protocol. */ private static final String PROTOCOL = "http"; /** HttpClients mock. */ private HttpClients httpClients; /** CloseableHttpClient mock. */ private CloseableHttpClient client; /** CloseableHttpClient mock. */ private CloseableHttpResponse response = Mockito.mock(CloseableHttpResponse.class); /** Our output. */ private ByteArrayOutputStream output; /** Our input. */ private ByteArrayInputStream input; /** Instance under tests. */ private SimpleHTTPPostPersistWriter writer; @Before public void setUp() throws Exception { this.httpClients = PowerMockito.mock(HttpClients.class); this.client = PowerMockito.mock(CloseableHttpClient.class); PowerMockito.mockStatic(HttpClients.class); PowerMockito.when(HttpClients.createDefault()).thenReturn(client); PowerMockito.when(client.execute(any(HttpUriRequest.class))).thenReturn(response); Mockito.when(response.getEntity()).thenReturn(null); Mockito.doNothing().when(response).close(); } @Test public void testPersist() throws Exception { HttpPersistWriterConfiguration configuration = new HttpPersistWriterConfiguration(); configuration.setProtocol(PROTOCOL); configuration.setHostname(HOSTNAME); configuration.setPort(new Long(PORT)); configuration.setResourcePath("/"); this.writer = new SimpleHTTPPostPersistWriter(configuration); this.writer.prepare(null); StreamsDatum testDatum = new StreamsDatum(mapper.readValue("{\"message\":\"ping\"}", ObjectNode.class)); this.writer.write(testDatum); Mockito.verify(this.client).execute(any(HttpUriRequest.class)); Mockito.verify(this.response).close(); } }
/** Test copying documents between two indexes on same cluster */ @ElasticsearchIntegrationTest.ClusterScope( scope = ElasticsearchIntegrationTest.Scope.TEST, numNodes = 1) public class MongoElasticsearchSyncIT extends ElasticsearchIntegrationTest { private static final Logger LOGGER = LoggerFactory.getLogger(MongoElasticsearchSyncIT.class); ObjectMapper MAPPER = StreamsJacksonMapper.getInstance(); MongoElasticsearchSyncConfiguration syncConfiguration; int srcCount = 0; @Before public void prepareTest() throws Exception { syncConfiguration = MAPPER.readValue( MongoElasticsearchSyncIT.class.getResourceAsStream("/testSync.json"), MongoElasticsearchSyncConfiguration.class); syncConfiguration.getDestination().setClusterName(cluster().getClusterName()); MongoPersistWriter setupWriter = new MongoPersistWriter(syncConfiguration.getSource()); setupWriter.prepare(null); InputStream testActivityFolderStream = MongoElasticsearchSyncIT.class.getClassLoader().getResourceAsStream("activities"); List<String> files = IOUtils.readLines(testActivityFolderStream, Charsets.UTF_8); for (String file : files) { LOGGER.info("File: " + file); InputStream testActivityFileStream = MongoElasticsearchSyncIT.class.getClassLoader().getResourceAsStream("activities/" + file); Activity activity = MAPPER.readValue(testActivityFileStream, Activity.class); activity.getAdditionalProperties().remove("$license"); StreamsDatum datum = new StreamsDatum(activity, activity.getVerb()); setupWriter.write(datum); LOGGER.info("Wrote: " + activity.getVerb()); srcCount++; } setupWriter.cleanUp(); } @Test public void testSync() throws Exception { assert srcCount > 0; MongoElasticsearchSync sync = new MongoElasticsearchSync(syncConfiguration); Thread reindexThread = new Thread(sync); reindexThread.start(); reindexThread.join(); flushAndRefresh(); assert (indexExists("destination")); long destCount = client().count(client().prepareCount("destination").request()).get().getCount(); assert srcCount == destCount; } }
public class MongoPersistWriter implements StreamsPersistWriter, Runnable { public static final String STREAMS_ID = "MongoPersistWriter"; private static final Logger LOGGER = LoggerFactory.getLogger(MongoPersistWriter.class); private static final long MAX_WRITE_LATENCY = 1000; protected volatile Queue<StreamsDatum> persistQueue; private ObjectMapper mapper = StreamsJacksonMapper.getInstance(); private volatile AtomicLong lastWrite = new AtomicLong(System.currentTimeMillis()); private ScheduledExecutorService backgroundFlushTask = Executors.newSingleThreadScheduledExecutor(); private MongoConfiguration config; protected DB client; protected DBAddress dbaddress; protected DBCollection collection; protected List<DBObject> insertBatch = Lists.newArrayList(); protected final ReadWriteLock lock = new ReentrantReadWriteLock(); public MongoPersistWriter() { this(MongoConfigurator.detectConfiguration(StreamsConfigurator.config.getConfig("mongo"))); } public MongoPersistWriter(MongoConfiguration config) { this.config = config; } public void setPersistQueue(Queue<StreamsDatum> persistQueue) { this.persistQueue = persistQueue; } public Queue<StreamsDatum> getPersistQueue() { return persistQueue; } @Override public String getId() { return STREAMS_ID; } @Override public void write(StreamsDatum streamsDatum) { DBObject dbObject = prepareObject(streamsDatum); if (dbObject != null) { addToBatch(dbObject); flushIfNecessary(); } } public void flush() throws IOException { try { LOGGER.debug("Attempting to flush {} items to mongo", insertBatch.size()); lock.writeLock().lock(); collection.insert(insertBatch); lastWrite.set(System.currentTimeMillis()); insertBatch = Lists.newArrayList(); } finally { lock.writeLock().unlock(); } } public synchronized void close() throws IOException { client.cleanCursors(true); backgroundFlushTask.shutdownNow(); } public void start() { connectToMongo(); backgroundFlushTask.scheduleAtFixedRate( new Runnable() { @Override public void run() { flushIfNecessary(); } }, 0, MAX_WRITE_LATENCY * 2, TimeUnit.MILLISECONDS); } public void stop() { try { flush(); } catch (IOException e) { LOGGER.error("Error flushing", e); } try { close(); } catch (IOException e) { LOGGER.error("Error closing", e); } try { backgroundFlushTask.shutdown(); // Wait a while for existing tasks to terminate if (!backgroundFlushTask.awaitTermination(15, TimeUnit.SECONDS)) { backgroundFlushTask.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!backgroundFlushTask.awaitTermination(15, TimeUnit.SECONDS)) { LOGGER.error("Stream did not terminate"); } } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted backgroundFlushTask.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } @Override public void run() { while (true) { if (persistQueue.peek() != null) { try { StreamsDatum entry = persistQueue.remove(); write(entry); } catch (Exception e) { e.printStackTrace(); } } try { Thread.sleep(new Random().nextInt(1)); } catch (InterruptedException e) { } } } @Override public void prepare(Object configurationObject) { this.persistQueue = new ConcurrentLinkedQueue<StreamsDatum>(); start(); } @Override public void cleanUp() { stop(); } protected void flushIfNecessary() { long lastLatency = System.currentTimeMillis() - lastWrite.get(); // Flush iff the size > 0 AND the size is divisible by 100 or the time between now and the last // flush is greater // than the maximum desired latency if (insertBatch.size() > 0 && (insertBatch.size() % 100 == 0 || lastLatency > MAX_WRITE_LATENCY)) { try { flush(); } catch (IOException e) { LOGGER.error("Error writing to Mongo", e); } } } protected void addToBatch(DBObject dbObject) { try { lock.readLock().lock(); insertBatch.add(dbObject); } finally { lock.readLock().unlock(); } } protected DBObject prepareObject(StreamsDatum streamsDatum) { DBObject dbObject = null; if (streamsDatum.getDocument() instanceof String) { dbObject = (DBObject) JSON.parse((String) streamsDatum.getDocument()); } else { try { ObjectNode node = mapper.valueToTree(streamsDatum.getDocument()); dbObject = (DBObject) JSON.parse(node.toString()); } catch (Exception e) { e.printStackTrace(); LOGGER.error("Unsupported type: " + streamsDatum.getDocument().getClass(), e); } } return dbObject; } private synchronized void connectToMongo() { try { client = new MongoClient(config.getHost(), config.getPort().intValue()).getDB(config.getDb()); } catch (UnknownHostException e) { e.printStackTrace(); return; } if (!Strings.isNullOrEmpty(config.getUser()) && !Strings.isNullOrEmpty(config.getPassword())) client.authenticate(config.getUser(), config.getPassword().toCharArray()); if (!client.collectionExists(config.getCollection())) { client.createCollection(config.getCollection(), null); } ; collection = client.getCollection(config.getCollection()); } }