Flink How to Write DataSet As Parquet files in S3? - apache-flink

How to write DataSet as Parquet files in s3 bucket using Flink. Is there any direct function like spark : DF.write.parquet("write in parquet")
Please help me how to write flink Dataset in parquet format.
I am stuck when trying to convert my DataSet to (Void,GenericRecord)
DataSet<Tuple2<Void,GenericRecord>> df = allEvents.flatMap(new FlatMapFunction<Tuple2<LongWritable, Text>, Tuple2<Void, GenericRecord>>() {
#Override
public void flatMap(Tuple2<LongWritable, Text> longWritableTextTuple2, Collector<Tuple2<Void, GenericRecord>> collector) throws Exception {
JsonAvroConverter converter = new JsonAvroConverter();
Schema schema = new Schema.Parser().parse(new File("test.avsc"));
try {
GenericRecord record = converter.convertToGenericDataRecord(longWritableTextTuple2.f1.toString().getBytes(), schema);
collector.collect( new Tuple2<Void,GenericRecord>(null,record));
}
catch (Exception e) {
System.out.println("error in converting to avro")
}
}
});
Job job = Job.getInstance();
HadoopOutputFormat parquetFormat = new HadoopOutputFormat<Void, GenericRecord>(new AvroParquetOutputFormat(), job);
FileOutputFormat.setOutputPath(job, new Path(outputPath));
df.output(parquetFormat);
env.execute();
Please help me with what I am doing wrong. I am getting Exception and this
code is not working.

It's a little more complicated than that with Spark. The only way I was able to read and write Parquet data in Flink is through Hadoop & MapReduce compatibility. You need hadoop-mapreduce-client-core and flink-hadoop-compatibility in Your dependencies.
Then You need to create a proper HadoopOutoutFormat. You need to do something like this:
val job = Job.getInstance()
val hadoopOutFormat = new hadoop.mapreduce.HadoopOutputFormat[Void, SomeType](new AvroParquetOutputFormat(), job)
FileOutputFormat.setOutputPath(job, [somePath])
And then You can do:
dataStream.writeUsingOutputFormat(hadoopOutFormat)

You didn't say which exception you are getting but here is a complete example on how to achieve this.
The main points are:
Use org.apache.flink.api.java.hadoop.mapreduce.HadoopOutputFormat
From dependency org.apache.flink:flink-hadoop-compatibility_2.11:1.11.0
HadoopOutputFormat is an adapter that allows you to use output formats developed for Hadoop
You need a DataSet<Tuple2<Void,IndexedRecord>>, because hadoop's OutputFormat<K,V> works with key-value pairs, the key we are not interested in so we use Void for the key type, and the value needs to be an Avro's IndexedRecord or GenericRecord.
Use org.apache.parquet.avro.AvroParquetOutputFormat<IndexedRecord>
From dependency org.apache.parquet:parquet-avro:1.11.1
This hadoop's OutputFormat produces Parquet
This inherits from org.apache.parquet.hadoop.FileOutputFormat<Void, IndexedRecord>
Create your own subclass of IndexedRecord
You can't use new GenericData.Record(schema) because a record like this is no serializable java.io.NotSerializableException: org.apache.avro.Schema$Field is not serializable and Flink requires it to be serializable.
You still need to provide a getSchema() method, but you can either return null or return a Schema that you hold in a static member (so that it doesn't need to be serialized, and you avoid the java.io.NotSerializableException: org.apache.avro.Schema$Field is not serializable)
The source code
import org.apache.avro.Schema;
import org.apache.avro.generic.IndexedRecord;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.hadoop.mapreduce.HadoopOutputFormat;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.parquet.avro.AvroParquetOutputFormat;
import org.apache.parquet.hadoop.metadata.CompressionCodecName;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class MyParquetTest implements Serializable {
public static void main(String[] args) throws Exception {
new MyParquetTest().start();
}
private void start() throws Exception {
final ExecutionEnvironment env = ExecutionEnvironment.createLocalEnvironment();
Configuration parameters = new Configuration();
Stream<String> stringStream = IntStream.range(1, 100).mapToObj(n -> String.format("Entry %d", n));
DataSet<String> text = env.fromCollection(stringStream.collect(Collectors.toCollection(ArrayList::new)));
Job job = Job.getInstance();
HadoopOutputFormat<Void, IndexedRecord> hadoopOutputFormat = new HadoopOutputFormat<>(new AvroParquetOutputFormat<IndexedRecord>(), job);
FileOutputFormat.setCompressOutput(job, true);
FileOutputFormat.setOutputCompressorClass(job, CompressionCodecName.SNAPPY.getHadoopCompressionCodecClass());
FileOutputFormat.setOutputPath(job, new org.apache.hadoop.fs.Path("./my-parquet"));
final Schema schema = new Schema.Parser().parse(MyRecord.class.getClassLoader().getResourceAsStream("schema.avsc"));
AvroParquetOutputFormat.setSchema(job, schema);
DataSet<Tuple2<Void, IndexedRecord>> text2 = text.map(new MapFunction<String, Tuple2<Void, IndexedRecord>>() {
#Override
public Tuple2<Void, IndexedRecord> map(String value) throws Exception {
return Tuple2.of(null, new MyRecord(value));
// IndexedRecord record = new GenericData.Record(schema); // won't work becuase Schema$Field is not serializable
// record.put(0, value);
// return Tuple2.of(null, record);
}
});
text2.output(hadoopOutputFormat);
env.execute("Flink Batch Java API Skeleton");
}
public static class MyRecord implements IndexedRecord {
private static Schema schema;
static {
try {
schema = new Schema.Parser().parse(MyRecord.class.getClassLoader().getResourceAsStream("schema.avsc"));
} catch (IOException e) {
e.printStackTrace();
}
}
private final String value;
public MyRecord(String value) {
this.value= value;
}
#Override
public void put(int i, Object v) {
throw new NotImplementedException("You can't update this IndexedRecord");
}
#Override
public Object get(int i) {
return this.value;
}
#Override
public Schema getSchema() {
return schema; // or just return null and remove the schema member
}
}
}
The schema.avsc is simply
{
"name": "aa",
"type": "record",
"fields": [
{"name": "value", "type": "string"}
]
}
and the dependencies:
implementation "org.apache.flink:flink-java:${flinkVersion}"
implementation "org.apache.flink:flink-avro:${flinkVersion}"
implementation "org.apache.flink:flink-streaming-java_${scalaBinaryVersion}:${flinkVersion}"
implementation "org.apache.flink:flink-hadoop-compatibility_${scalaBinaryVersion}:${flinkVersion}"
implementation "org.apache.parquet:parquet-avro:1.11.1"
implementation "org.apache.hadoop:hadoop-client:2.8.3"

You'll create a Flink OutputFormat via new HadoopOutputFormat(parquetOutputFormat, job), and then pass that to DataSet.output(xxx).
The job comes from...
import org.apache.hadoop.mapreduce.Job;
...
Job job = Job.getInstance();
The parquetOutputFormat is created via:
import org.apache.parquet.hadoop.ParquetOutputFormat;
...
ParquetOutputFormat<MyOutputType> parquetOutputFormat = new ParquetOutputFormat<>();
See https://javadoc.io/doc/org.apache.parquet/parquet-hadoop/1.10.1/org/apache/parquet/hadoop/ParquetOutputFormat.html

Related

Check pointing is not working with dynamodb streams record in flink

How do a checkpoint the processed records in apache flink? same messages are being consumed at regular intervals.
Do I need to explicitly checkpoint each message post consumption?
I can see the eventId and sequenceNumber are matching for multiple messages being consumed.
It seems the checkpointing is not done and so same messages are retrieved from steams at regular intervals.
Here is the code
package com.flink.basics;
import org.apache.flink.api.common.state.ListState;
import org.apache.flink.api.common.state.ListStateDescriptor;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.kinesis.shaded.com.amazonaws.services.dynamodbv2.model.AttributeValue;
import org.apache.flink.kinesis.shaded.com.amazonaws.services.dynamodbv2.model.Record;
import org.apache.flink.kinesis.shaded.com.amazonaws.services.kinesis.clientlibrary.lib.worker.PreparedCheckpointer;
import org.apache.flink.runtime.state.filesystem.FsStateBackend;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.CheckpointConfig;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.streaming.api.functions.sink.DiscardingSink;
import org.apache.flink.streaming.connectors.kinesis.FlinkDynamoDBStreamsConsumer;
import org.apache.flink.streaming.connectors.kinesis.config.AWSConfigConstants;
import org.apache.flink.streaming.connectors.kinesis.config.ConsumerConfigConstants;
import org.apache.flink.streaming.connectors.kinesis.serialization.DynamoDBStreamsSchema;
import org.apache.flink.util.Collector;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Properties;
public class DynamoDbConsumer {
public static void main(String[] args) throws Exception {
Properties consumerConfig = new Properties();
consumerConfig.put(AWSConfigConstants.AWS_REGION, "us-east-1");
consumerConfig.put(AWSConfigConstants.AWS_ACCESS_KEY_ID, "aws_access_key_id");
consumerConfig.put(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "aws_secret_access_key");
consumerConfig.put(AWSConfigConstants.AWS_ENDPOINT, "http://localhost:4566");
consumerConfig.put(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "LATEST");
System.setProperty("com.amazonaws.sdk.disableCbor", "true");
System.setProperty("org.apache.flink.kinesis.shaded.com.amazonaws.sdk.disableCbor", "true");
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(1000, CheckpointingMode.EXACTLY_ONCE);
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
// File based Backend
env.setStateBackend(new FsStateBackend(Paths.get("/Users/polimea/flink-basics/stbackend").toUri(), false));
FlinkDynamoDBStreamsConsumer<Record> flinkConsumer = new FlinkDynamoDBStreamsConsumer<Record>(
Collections.singletonList("arn:aws:dynamodb:us-east-1:000000000000:table/FDXTable/stream/2022-05-24T00:18:12.500"),
new DynamoDBStreamsSchema(), consumerConfig);
DataStream<Record> kinesisDBStream = env.addSource(flinkConsumer);
KeyedStream<Record, String> snapshotKeyedStream = kinesisDBStream.keyBy((KeySelector<Record, String>)
record -> record.getDynamodb().getNewImage().get("SNP").getS());
SingleOutputStreamOperator<Tuple2<String, Record>> records = snapshotKeyedStream.process(new StatefulReduceFunc());
records.print();
records.addSink(new DiscardingSink<>());
snapshotKeyedStream.process(new KeyedProcessFunction<String, Record, Object>() {
#Override
public void processElement(Record record, KeyedProcessFunction<String, Record, Object>.Context context,
Collector<Object> collector) throws Exception {
}
});
// kinesisDBStream.print();
env.execute("Stream for buffering dynamodb records till snapshot is committed");
}
private static class StatefulReduceFunc extends KeyedProcessFunction<String, Record, Tuple2<String, Record>> {
private transient ListState<Record> records;
public void open(Configuration parameters) {
ListStateDescriptor<Record> listStateDescriptor =
new ListStateDescriptor<>("records", Record.class);
records = getRuntimeContext().getListState(listStateDescriptor);
}
#Override
public void processElement(Record record, Context context,
Collector<Tuple2<String, Record>> collector) throws Exception {
Iterable<Record> recordIterator = this.records.get();
AttributeValue snCommitted = record.getDynamodb().getNewImage().get("SNCommitted");
if (snCommitted != null && snCommitted.getBOOL()) {
for (Record recordInList : recordIterator) {
collector.collect(new Tuple2<>(record.getDynamodb().getNewImage().get("SNP").getS(), recordInList));
}
} else {
records.add(record);
}
}
}
}
Not sure if this is related to your issue but the code you provided will buffer the records forever. I think what you want is to emit records and clear the state once commit message comes. Something along those lines
// ...
if (snCommitted != null && snCommitted.getBOOL()) {
var snp = record.getDynamodb().getNewImage().get("SNP").getS();
for (Record recordInList : recordIterator) {
collector.collect(new Tuple2<>(snp, recordInList));
}
// explicitly clear the buffer not to emit same events over and over again
records.clear();
}
// ...

How can I add message key to KafkaSink in Apache Flink 1.14

As stated in the title I need to set a custom message key in KafkaSink. I cannot find any indication on how to achieve this in the Apache Flink 1.14 docs.
At the moment I'm correctly setting up the KafkaSink and the data payload is correctly written in the topic, but the key is null.
Any suggestions? Thanks in advance
You should implement a KafkaRecordSerializationSchema that sets the key on the ProducerRecord returned by its serialize method.
You'll create the sink more-or-less like this:
KafkaSink<UsageRecord> sink =
KafkaSink.<UsageRecord>builder()
.setBootstrapServers(brokers)
.setKafkaProducerConfig(kafkaProps)
.setRecordSerializer(new MyRecordSerializationSchema(topic))
.setDeliverGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
.setTransactionalIdPrefix("my-record-producer")
.build();
and the serializer will be something like this:
public class MyRecordSerializationSchema implements
KafkaRecordSerializationSchema<T> {
private static final long serialVersionUID = 1L;
private String topic;
private static final ObjectMapper objectMapper =
JsonMapper.builder()
.build()
.registerModule(new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
public MyRecordSerializationSchema() {}
public MyRecordSerializationSchema(String topic) {
this.topic = topic;
}
#Override
public ProducerRecord<byte[], byte[]> serialize(
T element, KafkaSinkContext context, Long timestamp) {
try {
return new ProducerRecord<>(
topic,
null, // choosing not to specify the partition
element.ts.toEpochMilli(),
element.getKey(),
objectMapper.writeValueAsBytes(element));
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(
"Could not serialize record: " + element, e);
}
}
}
Note that this example is also setting the timestamp.
FWIW, this example comes from https://github.com/alpinegizmo/flink-mobile-data-usage/blob/main/src/main/java/com/ververica/flink/example/datausage/records/UsageRecordSerializationSchema.java.
This example is for scala programmers. Here, we are defining a key by generating UUID for each events.
import org.apache.flink.connector.kafka.sink.KafkaRecordSerializationSchema
import org.apache.kafka.clients.producer.ProducerRecord
import java.lang
class MyRecordSerializationSchema extends KafkaRecordSerializationSchema[String] {
override def serialize(element: String, context: KafkaRecordSerializationSchema.KafkaSinkContext, timestamp: lang.Long): ProducerRecord[Array[Byte], Array[Byte]] = {
return new ProducerRecord(
kafkaTopicName,
java.util.UUID.randomUUID.toString.getBytes,
element.getBytes
)
}
}
In the main class, will have to pass an instance of this class while defining the kafka sink like this:
val sinkKafka: KafkaSink[String] = KafkaSink.builder()
.setBootstrapServers(bootstrapServerUrl) //Bootstrap server url
.setRecordSerializer(new MyRecordSerializationSchema())
.build()

Manipulating query using Custom Query Parser in Solr

I have tried to create a CustomQueryParser where I am making use of OpenNLP libraries as well.
My objective is if i have a query "How many defective rims are causing failure in ABC tyres in China"
I want the final query to be something like "defective rims failure tyres China"
which then would go to the Analyzer for further processing.
This is my code for QueryParserPlugin -
package com.mycompany.lucene.search;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.QParser;
import org.apache.solr.search.QParserPlugin;
import com.mycompany.lucene.search.QueryParser;
public class QueryParserPlugin extends QParserPlugin {
#Override
public QParser createParser(String qstr, SolrParams localParams,
SolrParams params, SolrQueryRequest req) {
return new QueryParser(qstr, localParams, params, req, "body_txt_str");
}
}
And the code for my QueryParser -
package com.mycompany.lucene.search;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.search.QParser;
import org.apache.solr.search.SyntaxError;
import opennlp.tools.postag.POSModel;
import opennlp.tools.postag.POSTaggerME;
import opennlp.tools.tokenize.Tokenizer;
import opennlp.tools.tokenize.TokenizerME;
import opennlp.tools.tokenize.TokenizerModel;
public class QueryParser extends QParser {
private String fieldName;
public QueryParser(String qstr, SolrParams localParams, SolrParams params,
SolrQueryRequest req,
String defaultFieldName) {
super(qstr, localParams, params, req);
fieldName = localParams.get("field");
if (fieldName == null) {
fieldName = params.get("df");
}
}
#Override
public Query parse() throws SyntaxError {
Analyzer analyzer = req.getSchema().getQueryAnalyzer();
InputStream tokenModelIn = null;
InputStream posModelIn = null;
try {
tokenModelIn = new FileInputStream("/Files/en-token.bin");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
TokenizerModel tokenModel = null;
try {
tokenModel = new TokenizerModel(tokenModelIn);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Tokenizer tokenizer = new TokenizerME(tokenModel);
String tokens[] = tokenizer.tokenize(qstr);
try {
posModelIn = new FileInputStream("/Files/en-pos-maxent.bin");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// loading the parts-of-speech model from stream
POSModel posModel = null;
try {
posModel = new POSModel(posModelIn);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// initializing the parts-of-speech tagger with model
POSTaggerME posTagger = new POSTaggerME(posModel);
// Tagger tagging the tokens
String tags[] = posTagger.tag(tokens);
String final_query = "";
for(int i=0;i<tokens.length;i++){
if (tags[i]=="JJ" || tags[i]=="NNS" || tags[i]=="NN") {
final_query = final_query + " " +tokens[i];
}
}
TermQuery tq= new TermQuery(new Term(fieldName,final_query));
return tq;
}
}
I then exported this as a jar and added these jars to my solrconfig.xml -
<lib dir="${solr.install.dir:../../../..}/contrib/customparser/lib"
regex=".*\.JAR" />
<lib dir="${solr.install.dir:../../../..}/contrib/analysis-extras/lib"
regex="opennlp-.*\.jar" />
But getting the below error :
Caused by:
java.lang.NoClassDefFoundError: opennlp/tools/tokenize/Tokenizer
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at org.apache.solr.core.SolrResourceLoader.findClass(SolrResourceLoader.java:541)
at org.apache.solr.core.SolrResourceLoader.findClass(SolrResourceLoader.java:488)
at org.apache.solr.core.SolrCore.createInstance(SolrCore.java:786)
at org.apache.solr.core.PluginBag.createPlugin(PluginBag.java:135)
at org.apache.solr.core.PluginBag.init(PluginBag.java:271)
at org.apache.solr.core.PluginBag.init(PluginBag.java:260)
at org.apache.solr.core.SolrCore.<init>(SolrCore.java:957)
... 9 more
This is my first time creating a CustomQueryParser, Could you please help me out.
Thanks
most probably your path
${solr.install.dir:../../../..}/contrib/analysis-extras/lib
doesn't contain the relevant opennlp jars or the regex is not appropriate.
that's the first thing to check.
you have to either "bundle" also the opennlp dependencies in your custom query parser jar (e.g. if you use maven to build your project, using maven-assembly-plugin, maven-shade-plugin, etc.) or make sure the opennlp specific jars in the relevant directive in your solrconfig.xml are matched.

How to filter Apache flink stream on the basis of other?

I have two stream one is of Int and other is of json .In The json Schema there is one key which is some int .So i need to filter the json stream via key comparison with the other integer stream so Is it possible in Flink?
Yes, you can do this kind of stream processing with Flink. The basic building blocks you need from Flink are connected streams, and stateful functions -- here's an example using a RichCoFlatMap:
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.common.typeinfo.TypeHint;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.co.RichCoFlatMapFunction;
import org.apache.flink.util.Collector;
public class Connect {
public static void main(String[] args) throws Exception {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<Event> control = env.fromElements(
new Event(17),
new Event(42))
.keyBy("key");
DataStream<Event> data = env.fromElements(
new Event(2),
new Event(42),
new Event(6),
new Event(17),
new Event(8),
new Event(42)
)
.keyBy("key");
DataStream<Event> result = control
.connect(data)
.flatMap(new MyConnectedStreams());
result.print();
env.execute();
}
static final class MyConnectedStreams
extends RichCoFlatMapFunction<Event, Event, Event> {
private ValueState<Boolean> seen = null;
#Override
public void open(Configuration config) {
ValueStateDescriptor<Boolean> descriptor = new ValueStateDescriptor<>(
// state name
"have-seen-key",
// type information of state
TypeInformation.of(new TypeHint<Boolean>() {
}));
seen = getRuntimeContext().getState(descriptor);
}
#Override
public void flatMap1(Event control, Collector<Event> out) throws Exception {
seen.update(Boolean.TRUE);
}
#Override
public void flatMap2(Event data, Collector<Event> out) throws Exception {
if (seen.value() == Boolean.TRUE) {
out.collect(data);
}
}
}
public static final class Event {
public Event() {
}
public Event(int key) {
this.key = key;
}
public int key;
public String toString() {
return String.valueOf(key);
}
}
}
In this example, only those keys that have been seen on the control stream are passed through the data stream -- all other events are filtered out. I've taken advantage of Flink's managed keyed state and connected streams.
To keep this simple I've ignored your requirement that the data stream has JSON, but you can find examples of how to work with JSON and Flink elsewhere.
Note that your results will be non-deterministic, since you have no control over the timing of the two streams relative to one another. You could manage this by adding event-time timestamps to the streams, and then using a RichCoProcessFunction instead.

injecting Session bean from another session bean in JBoss 7.1

I am not able to inject a SLSB in another SLSB. Actually created 3 projects
1) created a EJB project with an MDB
2) created a EJB project with a stateless session bean for posting the message
3) created a EJB project with a stateless session bean for injecting the above session bean
But while injecting I am not able to inject the EJB it is returning null
the code is as below
1) MDB:
#MessageDriven(
activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "activemq/queue/TestQueue"),
#ActivationConfigProperty(propertyName="acknowledgeMode", propertyValue="Auto-acknowledge")
})
#ResourceAdapter("activemq-ra.rar")
public class ConsumerMDB implements MessageListener {
public void onMessage(Message message) {
try {
System.out.println("Queue: Received a TextMessage at " + new Date());
TextMessage msg = (TextMessage) message;
System.out.println("Message is : " + msg.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
2) Session Bean 1
package com.springboard.session;
import javax.annotation.Resource;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
#Stateless
#LocalBean
public class ProducerSession implements ProducerSessionLocal {
#Resource(mappedName="java:jboss/activemq/QueueConnectionFactory")
public static QueueConnectionFactory factory;
#Resource(mappedName = "java:jboss/activemq/queue/TestQueue")
public static Queue queue;
#Override
public void sendMessage(String msg) {
System.out.println("****************Entering into method********************");
try {
System.out.println(queue.getQueueName());
QueueConnection qConnection = factory.createQueueConnection();
QueueSession qSession = qConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
TextMessage message = qSession.createTextMessage();
message.setText(msg);
QueueSender qSender = qSession.createSender(queue);
qSender.send(message);
qSender.close();
qSession.close();
qConnection.close();
} catch (JMSException e) {
e.printStackTrace();
}
System.out.println("****************Exiting into method********************");
}
}
and the interface is
package com.springboard.session;
import javax.ejb.Local;
#Local
public interface ProducerSessionLocal {
public void sendMessage(String msg);
}
3) Second session bean to inject the first session
#Stateless
public class TestProducerLocalBean implements TestProducerLocalBeanLocal {
#EJB(mappedName = "java:global/ProducerSessionActiveMQ/ProducerSession!com.springboard.session.ProducerSessionLocal")
public ProducerSessionLocal producer;
public TestProducerLocalBean() {
System.out.println("*************Testing Producer****************");
if(producer!=null){
producer.sendMessage("This Message is from SessionBean to Session Bean to MDB");
}
else{
System.out.println("EJB is null");
}
System.out.println("**********End************************");
}
#Override
public void messageSend(String msg) {
// TODO Auto-generated method stub
}
and for testing purpose used a class
import javax.ejb.EJB;
import com.springboard.session.test.TestProducerLocalBean;
public class testEJB {
#EJB
public static TestProducerLocalBean local =new TestProducerLocalBean();
public static void main(String[] args) {
}
}
At producer EJB always retuns null. With using servlet to inject ProducerSession i am able to do it. but injecting with another EJB i not able to get it.
Could any one please help me out what i am missing
Thanks in advance
It's incorrect to use initialization ... = new Xyz() when using injection because initialization of those fields is the responsibility of the container. You probably attempted that because you noticed that the field was null, and that's because injection (including #EJB) is not supported in the main class unless you use an application client container.

Resources