Is there any way to create topologies dynamically in trident ?
Could anyone please provide examples ?
First of all, you might also know that creating topologies is not part of Trident. Trident is just an API for microbatching.
And creating new topologies is dynamic by definition. This is what the TopologyBuilder class is doing.
So to answer your question, yes it is possible to create new topologies from Trident, or from simple Storm spouts and bolts. The only thing you need is that your topology creating logic should have access to the Storm cluster (classes and other resources) which is again by definition satisfied if you run your logic in Storm.
The last thing you will need is to find a way to submit the newly created topology, and this is what the StormSubmitter class was made for, which is again (!surprise :) ) by definitions satisfied to be on your classpath when you run your logic inside a Trident or ordinary spout/bolt.
Out of curiosity, why are you planning to do this? What are your requirements?
Example:
import java.util.Map;
import org.apache.storm.Config;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.trident.operation.TridentCollector;
import org.apache.storm.trident.spout.IBatchSpout;
import org.apache.storm.tuple.Fields;
public class DynamicTopologySpout implements IBatchSpout {
private static final long serialVersionUID = -3269435263455830842L;
#Override
#SuppressWarnings("rawtypes")
public void open(Map conf, TopologyContext context) {}
#Override
public void emitBatch(long batchId, TridentCollector collector) {
if (newTopologyNeeded()) {
TopologyBuilder builder = new TopologyBuilder();
builder
.setSpout("spout", new BaseRichSpout() {
private static final long serialVersionUID = 1L;
#Override public void declareOutputFields(OutputFieldsDeclarer declarer) {}
#Override #SuppressWarnings("rawtypes") public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {}
#Override public void nextTuple() {}
}, 1)
.setMaxSpoutPending(15)
.setNumTasks(1);
StormTopology topology = builder.createTopology();
Config config = new Config();
try {
StormSubmitter.submitTopology("dynamic-topology", config, topology);
} catch (Exception e) {
e.printStackTrace();
collector.reportError(e);
}
}
}
private boolean newTopologyNeeded() {
// Check if topology needed ...
return false;
}
#Override
public void ack(long batchId) {}
#Override
public void close() {}
#Override
public Map<String, Object> getComponentConfiguration() { return null; }
#Override
public Fields getOutputFields() { return null; }
}
Related
I want to use separate configuration files for different bundles instead of using a single configuration/config.ini file. I am following this doc https://www.eclipse.org/equinox/documents/quickstart-framework.php .
I am not able to figure out how to achieve this. Any suggestion would be very helpful.
Thanks in advance.
Following links solve the problem I was facing-
https://www.eclipse.org/forums/index.php/t/1072082/
https://git.eclipse.org/c/om2m/org.eclipse.om2m.git/tree/org.eclipse.om2m.site.mn-cse/configurations/services/lifx.basedriver.properties
https://git.eclipse.org/c/om2m/org.eclipse.om2m.git/tree/org.eclipse.om2m.sdt/org.eclipse.om2m.sdt.home.lifx/src/main/java/org/eclipse/om2m/sdt/home/lifx/impl/Activator.java
Steps I followed to achieve this -
Create configurations/services/<config_file_name>.properties having configurations in key-value pair. For example - property1 property1_value
Import package org.osgi.service.cm for your bundle
Use the following code
package <package_name>;
import java.util.Dictionary;
import java.util.Hashtable;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
public class Activator implements BundleActivator, ManagedService {
private static BundleContext context;
private ServiceRegistration managedServiceServiceRegistration;
static BundleContext getContext() {
return context;
}
public void start(BundleContext bundleContext) throws Exception {
Activator.context = bundleContext;
Dictionary properties = new Hashtable<>();
properties.put(Constants.SERVICE_PID, "config_file_name");
managedServiceServiceRegistration =
bundleContext.registerService(ManagedService.class.getName(), this, properties);
}
public void stop(BundleContext bundleContext) throws Exception {
Activator.context = null;
}
#Override
public void updated(Dictionary properties) throws ConfigurationException {
try {
System.out.println(properties.get("property1"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
I had implement CQRS+ES application using axon and spring-boot. I use separate query model and command model application. I use rabbitmq to publish event from command mode. It works correct. But tracking Processor implementation is not work in my application.
This is my query model
#SpringBootApplication
public class SeatQueryPart1Application {
public static void main(String[] args) {
SpringApplication.run(SeatQueryPart1Application.class, args);
}
#Bean
public SpringAMQPMessageSource statisticsQueue(Serializer serializer) {
return new SpringAMQPMessageSource(new DefaultAMQPMessageConverter(serializer)) {
#RabbitListener(exclusive = false, bindings = #QueueBinding(value = #Queue, exchange = #Exchange(value = "ExchangeTypesTests.FanoutExchange", type = ExchangeTypes.FANOUT), key = "orderRoutingKey"))
#Override
public void onMessage(Message arg0, Channel arg1) throws Exception {
super.onMessage(arg0, arg1);
}
};
}
#Autowired
public void conf(EventHandlingConfiguration configuration) {
configuration.registerTrackingProcessor("statistics");
}
}
this is a event handler class
#ProcessingGroup("statistics")
#Component
public class EventLoggingHandler {
private SeatReservationRepository seatReservationRepo;
public EventLoggingHandler(final SeatReservationRepository e) {
this.seatReservationRepo = e;
}
#EventHandler
protected void on(SeatResurvationCreateEvent event) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Seat seat=new Seat(event.getId(), event.getSeatId(), event.getDate(),timestamp ,true);
seatReservationRepo.save(seat);
}
}
this is yml configuration
axon:
eventhandling:
processors:
statistics.source: statisticsQueue
How can i do it correct. (Can anyone suggest tutorial or code sample)
The SpringAMQPMessageSource is a SubscribableMessageSource. This means you cannot use a tracking event processor to process messages. It is only compatible with a Subscribable Event Processor.
Removing configuration.registerTrackingProcessor("statistics"); and leaving it to the default (subscribing) should do the trick.
In my Storm based application I need to query oracle table periodically So I thought to use Tick tuple of storm. But it's not giving correct result and tick tuple is not producing.
My storm version is 1.0.1.2.5.3.0-37
I tried as below,
Added getComponentConfiguration method in bolt as http://www.michael-noll.com/blog/2013/01/18/implementing-real-time-trending-topics-in-storm/ link but tick tuple is not generating.
So I changed the code and used Config from topology for generating tick tuple.I refer https://www.safaribooksonline.com/blog/2014/01/06/multi-threading-storm/ link but here I got tick tuple only once.
Below is my code of tick tuple with bolt,
public class TickTupleBolt implements IRichBolt{
private OutputCollector collector = null;
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(TickTupleBolt.class);
public void prepare(Map stormConf, TopologyContext context,OutputCollector collector) {
this.collector = collector;
}
public void execute(Tuple tuple) {
LOG.info("Start of TickTupleBolt.execute");
try {
if (isTickTuple(tuple)) {
//if(tuple.getSourceStreamId().equals("__tick")){
LOG.info("**got tick tuple");
}else{
LOG.info("not got tick tuple");
}
} catch (Exception e) {
LOG.error("Bolt execute error: {}", e);
collector.reportError(e);
}
LOG.info("End of TickTupleBolt.execute");
}
public void cleanup() {
// TODO Auto-generated method stub
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// TODO Auto-generated method stub
}
public Map<String, Object> getComponentConfiguration() {
// configure how often a tick tuple will be sent to our bolt
Map<String, Object> conf = new HashMap<String, Object>();
conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 1);
return conf;
}
protected boolean isTickTuple(Tuple tuple) {
return tuple.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID)
&& tuple.getSourceStreamId().equals(Constants.SYSTEM_TICK_STREAM_ID);
}
}
I got one link Tick Tuple not functioning in apache storm 0.9.4 but there is no answer.
So can any body please let me know,
How to implement tick tuple in Storm
Is there any other way (apart from tick tuple) to do periodic job in storm
UPDATE - Topology Code
My Topology builder,
public class Topology {
private static final Logger LOG = LoggerFactory.getLogger(Topology.class);
public static StormTopology buildTopology() {
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("tickspout", new TickTupleSpout());
builder.setBolt("tickbolt", new TickTupleBolt()).shuffleGrouping("tickspout");
return builder.createTopology();
}
public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException, AuthorizationException {
Config conf = new Config();
//conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 5);//tried it also
conf.setDebug(true);
//conf.setNumWorkers(2);
StormSubmitter.submitTopology(args[0], conf, buildTopology());
}
}
UPDATE - Spout Code
public class TickTupleSpout extends BaseRichSpout{
private static final Logger LOG = LoggerFactory.getLogger(TickTupleSpout.class);
private static final long serialVersionUID = 1L;
private SpoutOutputCollector collector;
public TickTupleSpout() {
}
public void open(Map conf, TopologyContext context,
SpoutOutputCollector collector) {
// TODO Auto-generated method stub
LOG.info("Start of TickTupleSpout.Open");
this.collector = collector;
LOG.info("End of TickTupleSpout.Open");
}
public void nextTuple() {
LOG.info("Start of TickTupleSpout.nextTuple");
this.collector.emit(new Values("0");//just send dummy value
LOG.info("End of TickTupleSpout.nextTuple");
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("breachdata"));
}
//public Map<String, Object> getComponentConfiguration() {
//Config conf = new Config();
//int tickFrequencyInSeconds = 5;
//conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, tickFrequencyInSeconds);
//return conf;
//}
}
Thanks.
I am trying to do an Jetty Web Socket example .
I copied a example from internet , which was working fine when i deployed directly into server without making any chnages .
But when i copied the Source (the servlet) into Eclipse IDE , it was giving Compilation
Exceptions related to
The method onClose(int, String) of type Html5Servlet.StockTickerSocket must override a superclass method
- The method onOpen(WebSocket.Connection) of type Html5Servlet.StockTickerSocket must override a superclass method
The method onMessage(String) of type Html5Servlet.StockTickerSocket must override a superclass method
This is my servlet , i kept the jars as it is mentioned in that example
package org.ajeesh.app;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.websocket.WebSocket;
import org.eclipse.jetty.websocket.WebSocketServlet;
public class Html5Servlet extends WebSocketServlet {
private AtomicInteger index = new AtomicInteger();
private static final List<String> tickers = new ArrayList<String>();
static{
tickers.add("ajeesh");
tickers.add("peeyu");
tickers.add("kidillan");
tickers.add("entammo");
}
/**
*
*/
private static final long serialVersionUID = 1L;
public WebSocket doWebSocketConnect(HttpServletRequest req, String resp) {
System.out.println("On server");
return new StockTickerSocket();
}
protected String getMyJsonTicker(){
StringBuilder start=new StringBuilder("{");
start.append("\"stocks\":[");
int counter=0;
for (String aTicker : tickers) {
counter++;
start.append("{ \"ticker\":\""+aTicker +"\""+","+"\"price\":\""+index.incrementAndGet()+"\" }");
if(counter<tickers.size()){
start.append(",");
}
}
start.append("]");
start.append("}");
return start.toString();
}
public class StockTickerSocket implements WebSocket.OnTextMessage{
private Connection connection;
private Timer timer;
#Override
public void onClose(int arg0, String arg1) {
System.out.println("Web socket closed!");
}
#Override
public void onOpen(Connection connection) {
System.out.println("onOpen!");
this.connection=connection;
this.timer=new Timer();
}
#Override
public void onMessage(String data) {
System.out.println("onMessage!");
if(data.indexOf("disconnect")>=0){
connection.close();
timer.cancel();
}else{
sendMessage();
}
}
private void sendMessage() {
System.out.println("sendMessage!");
if(connection==null||!connection.isOpen()){
System.out.println("Connection is closed!!");
return;
}
timer.schedule(new TimerTask() {
#Override
public void run() {
try{
System.out.println("Running task");
connection.sendMessage(getMyJsonTicker());
}
catch (IOException e) {
e.printStackTrace();
}
}
}, new Date(),5000);
}
}
}
I can't help but think that there is a very easy solution but no luck so far.
I think I've gone to the edge of the internet and back looking, read the whole RFC6455 to understand what's going on behind scenes, etc.
I use eclipse for development and have the latest tomcat running on development machine.
This is my test class that eclipse won't even compile because it suggests that I need to remove the #Override on the protected StreamInbound method. The actual wording:
The method createWebSocketInbound(String) of type wsListenerTest must override or implement a supertype method;
and it recommends removing the #Override.
I am trying to do everything native to Tomcat without any other servers or plugins.
Thanks in advance
package com.blah.blah;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;
import org.apache.catalina.websocket.WsOutbound;
public class wsListenerTest extends WebSocketServlet {
private static final long serialVersionUID = 1L;
static int numConnections = 0;
private static final String GUEST_PREFIX = "Guest";
private final AtomicInteger connectionIds = new AtomicInteger(0);
private final Set<ChatMessageInbound> connections = new CopyOnWriteArraySet<ChatMessageInbound>();
#Override
protected StreamInbound createWebSocketInbound(String subProtocol) {
return new ChatMessageInbound(connectionIds.incrementAndGet());
}
private final class ChatMessageInbound extends MessageInbound {
private final String nickname;
private ChatMessageInbound(int id) {
this.nickname = GUEST_PREFIX + id;
}
#Override
protected void onOpen(WsOutbound outbound) {
connections.add(this);
String message = String.format("* %s %s",
nickname, "has joined.");
broadcast(message);
}
#Override
protected void onClose(int status) {
connections.remove(this);
String message = String.format("* %s %s",
nickname, "has disconnected.");
broadcast(message);
}
#Override
protected void onBinaryMessage(ByteBuffer message) throws IOException {
throw new UnsupportedOperationException(
"Binary message not supported.");
}
#Override
protected void onTextMessage(CharBuffer message) throws IOException {
// Never trust the client
// String filteredMessage = String.format("%s: %s",nickname, HTMLFilter.filter(message.toString()));
broadcast(message.toString());
}
private void broadcast(String message) {
for (ChatMessageInbound connection : connections) {
try {
CharBuffer buffer = CharBuffer.wrap(message);
connection.getWsOutbound().writeTextMessage(buffer);
} catch (IOException ignore) {
// Ignore
}
}
}
}
}
I think the compiler is complaining about this #Override because the WebSocketServlet's createWebSocketInbound() method has the following
protected abstract StreamInbound createWebSocketInbound(String subProtocol,
HttpServletRequest request);
Try adding the HttpServletRequest parameter to your method and that should help to get you past this roadblock.