<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1890682579549650946</id><updated>2026-07-17T19:53:34.933+02:00</updated><category term="android"/><category term="3d"/><category term="apache kafka"/><category term="game development"/><category term="java"/><category term="#kafka"/><category term="#shiro"/><category term="#spring"/><category term="Apache Shiro"/><category term="Apache Shiro Java config"/><category term="Java config"/><category term="Spring MVC"/><category term="WebApplicationInitializer"/><category term="android apps"/><category term="android rajawali"/><category term="apache kafka tutorial"/><category term="cracking"/><category term="javacro"/><category term="kafka demo"/><category term="kotlin"/><category term="memory usage"/><category term="piracy"/><category term="programming language"/><category term="rajawali"/><category term="sencha android"/><title type='text'>Do Androids Dream of Electric Sheep?</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>9</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-8406360422634563305</id><published>2016-05-25T21:43:00.001+02:00</published><updated>2016-05-26T13:26:57.630+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="#kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="apache kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="javacro"/><category scheme="http://www.blogger.com/atom/ns#" term="kafka demo"/><title type='text'>Kafka demo at JavaCro conference </title><content type='html'>In my &lt;a href=&quot;http://beegor.blogspot.hr/2015/06/apache-kafka-first-contact.html&quot; target=&quot;_blank&quot;&gt;previous post &lt;/a&gt;(published almost a year ago), I tried to summarize basic concepts of &amp;nbsp;distributed messaging system called Kafka,&amp;nbsp;and to provide very basic tutorial for people who are new to this product.&lt;br /&gt;
At the end of that post I promised to give another &quot;how to&quot; once 0.9 version is released, version that introduces new consumers API. Version 0.9 is released six months ago, so I am little late with my promise, but better late then never :)&lt;br /&gt;
&lt;br /&gt;
Few days ago &lt;a href=&quot;http://2016.javacro.hr/eng/&quot; target=&quot;_blank&quot;&gt;JavaCro 2016&lt;/a&gt; conference was held in Rovinj, Croatia, where I presented basic Kafka concepts to (mostly) people&amp;nbsp;of croatian Java community and demonstrated simple spring Boot application using Kafka 0.9. &amp;nbsp;Since, I already explained basic Kafka concepts in previous post, this one will be focused on only on new consumer API and how to use it.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb2i8p_SZFsKDCBCz0mFnzeJTlZXjY43uXCA2k5aTlIff41XszlgTebXIiwDtz3Bqsst-H86_wiBxwZYU2D1QwGOaTXRv7bhMHEgSp_LlrO0Y2pbG5ygPKC0Tp08DgDhDlssz-6UZN26E/s1600/javacro_ib_kafka.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;480&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb2i8p_SZFsKDCBCz0mFnzeJTlZXjY43uXCA2k5aTlIff41XszlgTebXIiwDtz3Bqsst-H86_wiBxwZYU2D1QwGOaTXRv7bhMHEgSp_LlrO0Y2pbG5ygPKC0Tp08DgDhDlssz-6UZN26E/s640/javacro_ib_kafka.jpg&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Starting Kafka&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
So lets start with setup.&lt;br /&gt;
Download Kafka platform 2.0.1 from &lt;a href=&quot;http://packages.confluent.io/archive/2.0/confluent-2.0.1-2.11.7.zip&quot;&gt;http://packages.confluent.io/archive/2.0/confluent-2.0.1-2.11.7.zip&lt;/a&gt; and unzip it to location of your choice. Let&#39;s call this location confluent home folder.&lt;br /&gt;
&lt;br /&gt;
Now we can start Kafka server, but as explained in my previous post, Kafka requires&amp;nbsp;Apache ZooKeeper which is used for managing cluster configuration information.&lt;br /&gt;
&lt;br /&gt;
Navigate to confluent home folder and run :&lt;br /&gt;
&lt;i style=&quot;background-color: #fefdfa; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18.2px;&quot;&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;b&lt;/span&gt;&lt;/i&gt;&lt;span style=&quot;color: #38761d; font-family: &amp;quot;arial&amp;quot; , &amp;quot;tahoma&amp;quot; , &amp;quot;helvetica&amp;quot; , &amp;quot;freesans&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 13px; line-height: 18.2px;&quot;&gt;&lt;i&gt;in/zookeeper-server-start etc/kafka/zookeeper.properties&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And after it&#39;s up Kafka &amp;nbsp;broker can be started (in new terminal):&lt;br /&gt;
&lt;span style=&quot;color: #38761d; font-family: &amp;quot;arial&amp;quot; , &amp;quot;tahoma&amp;quot; , &amp;quot;helvetica&amp;quot; , &amp;quot;freesans&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 13px; line-height: 18.2px;&quot;&gt;&lt;i&gt;bin/kafka-server-start etc/kafka/server.properties&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Kafka is now started and ready to use. We started only one broker for testing purposes, but starting more brokers is trivial, only thing you need to prepare is another server.properties file since you want to configure different port then the one first broker is using.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Demo App&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
This demo app is spring boot web application which allows us to:&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;create Kafka topics,&amp;nbsp;&lt;/li&gt;
&lt;li&gt;start producers,&amp;nbsp;&lt;/li&gt;
&lt;li&gt;control producers speed&lt;/li&gt;
&lt;li&gt;start consumers&lt;/li&gt;
&lt;li&gt;control consumer message processing speed&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
You can find source code at &lt;a href=&quot;https://github.com/beegor/java-cro-kafka&quot; target=&quot;_blank&quot;&gt;github repository&lt;/a&gt;.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
Core package contains most important classes: JavaCroProducer and JavaCroConsumer. These classes represent our kafka clients and use producer and consumer api to talk to kafka cluster.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px;&quot;&gt;Video of the demo presented.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/1q9BDqqCGcw&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;

&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px;&quot;&gt;In this video we can see how to add topics, producers and consumers, and how Kafka automatically re-balances consumer while they connect or disconnect. Gears are used for showing current speed of consumers and producers, and progress like bars are used to display topic partition and their current message count.&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;h3&gt;
Producer&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
First, lets take a look at JavaCroProducer and see what we need to start it.&lt;/div&gt;
&lt;div&gt;
In order to communicate with Kafka (to send some messages to it) we need to create and configure KafkaProducer instance. I takes Properties object as argument so we must instantiate one and fill it with basic properties necessary for it to work.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;i&gt;&amp;nbsp; &lt;span style=&quot;color: #0b5394;&quot;&gt;Properties config = new Properties();&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; config.put(&quot;client.id&quot;, id);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; config.put(&quot;bootstrap.servers&quot;, &quot;localhost:9092&quot;);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; config.put(&quot;acks&quot;, &quot;1&quot;);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; KafkaProducer producer = new KafkaProducer&lt;string string=&quot;&quot;&gt;(config);&lt;/string&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;client.id &lt;/b&gt;property is used to uniquely identify our producer to Kafka cluster. In this case it is passed as constructor parameter of JavaCroProducer class. It&#39;s actually simple long incremented every time we create new JavaCroProducer instance.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;bootstrap.servers&lt;/b&gt; property is list of kafka broker identifiers consisting of host:port pairs, coma separated. We must provide at least one broker identifier, and if we have more then one broker in cluster it is recommended to provide two or more broker identifiers for redundancy. We don&#39;t have to provide all brokers identifiers, actually one is enough for producer to get all the info it needs, other identifiers are used just in case first broker fails or some other reason prevents producer to communicate with it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG&lt;/b&gt; is telling KafkaProducer which serializer to use for message keys &amp;nbsp;when sending messages to Kafka. In this example built in String serializer is used.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG&lt;/b&gt;&amp;nbsp;is telling KafkaProducer which serializer to use for message values &amp;nbsp;when sending messages to Kafka. In this example built in String serializer is used.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;acks &lt;/b&gt;property tells KafkaProducer when to consider a message successfully sent to Kafka broker. 0 value means that producer will consider message sent as soon as it puts it to socket buffer. Value 1 means thas message is considered sent when partition leader broker writes it to partition log, and finally value all means that producer will consider message sent only after partition leader and all it&#39;s replicas write message to partition log.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now we have our producer ready and we can us it to &amp;nbsp;send messages. Something like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;ProducerRecord record = new ProducerRecord(&quot;topicName&quot;, msgKey&quot;&quot;, &quot;msgValue&quot;);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;producer.send(record);&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
We need ProducerRecord instance &amp;nbsp;to send the message and it&#39;s constructor takes three arguments:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
-&lt;b&gt; topic name&lt;/b&gt; : string, name of kafka topic to which you want to send the message.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;message key&lt;/b&gt; &amp;nbsp;: object, &amp;nbsp;it is used to decide on which partition will message go if the topic has more then one partition. If message key is not null, every message with same key will go to same partition, so if we want all messages &amp;nbsp;with same business property (for example sender id) to end up on same partition, we could use that property as message key.&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
- &lt;b&gt;message value&lt;/b&gt; : string, &amp;nbsp;this is actual message payload - the content of the message.&lt;/div&gt;
&lt;div&gt;
Note that consumers will receive both message key and value so you can use key as some kind of extra message information holder.&lt;br /&gt;
&lt;br /&gt;
There is overloaded constructor which takes partition number instead of message key argument, and it is used to explicitly set target partition of the topic. KafkaProducer provides methods for discovering how many partition specific topic has.&lt;br /&gt;
&lt;br /&gt;
KafkaProducer.send() method is asynchronous but if we want to send the messages in synchronous way (not really recommended) we can do this, and here is how: send method returns&amp;nbsp;Future&lt;recordmetadata&gt; so we wait until we get sending result by calling Future.get() method on it.&amp;nbsp;&lt;/recordmetadata&gt;&lt;br /&gt;
&lt;br /&gt;
If we need to examine the result of send method but without blocking sending process, there is a way:&lt;br /&gt;
overloaded version of send method receives second argument, implementation of&amp;nbsp;&lt;b&gt;org.apache.kafka.clients.producer.Callback &lt;/b&gt;interface.&lt;br /&gt;
It&#39;s method&amp;nbsp;o&lt;i&gt;nCompletion(RecordMetadata metadata, Exception exception) &lt;/i&gt;will be called when message sending finishes, whether successfully or not&lt;i&gt;. &lt;/i&gt;If message is sent successfully we can get meta data from&amp;nbsp;RecordMetadata object (such as topic message was sent to, position of the message written to topic partition, number of partition which message was written to...) Second argument - Exception will be null if no error occurred, and not null otherwise.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Consumer&lt;/h3&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
JavaCroConsumer represents our consumer process and it uses&amp;nbsp;KafkaConsumer to communicate with Kafka cluster.&lt;/div&gt;
&lt;div&gt;
First thing to do is to create and configure KafkaConsumer object:&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;Properties config = new Properties();&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;config.put(&quot;client.id&quot;, id);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;config.put(&quot;group.id&quot;, group);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;config.put(&quot;bootstrap.servers&quot;, &quot;localhost:9092&quot;);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;config.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;config.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;config.put(&quot;auto.offset.reset&quot;, &quot;earliest&quot;);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;consumer = new KafkaConsumer(config);&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;consumer.subscribe( Arrays.asList(new String[]{topic}));&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
Let&#39;s go through all&amp;nbsp;KafkaConsumer config&amp;nbsp; properties :&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
-&lt;b&gt; client.id&lt;/b&gt;&amp;nbsp;: unique identifier of this consumer&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
-&amp;nbsp;&lt;b&gt;group.id &lt;/b&gt;: group we want consumer to belong to. &amp;nbsp;Group is&amp;nbsp;&amp;nbsp;set of consumers for handling specific business task (logical consumer).&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
-&amp;nbsp;&lt;b&gt;bootstrap.servers &lt;/b&gt;&lt;i&gt;:&amp;nbsp;&lt;/i&gt;list of kafka broker identifiers consisting of host:port pairs, coma separated. Like with producers, here we also &amp;nbsp;must provide at least one broker identifier, and if we have more then one broker in cluster it is recommended to provide two or more broker identifiers for redundancy.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
-&amp;nbsp;&lt;b&gt;ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG&lt;/b&gt; - deserializer implementation class for deserializing message keys&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
-&amp;nbsp;&lt;b&gt;ConsumerConfig.&lt;/b&gt;&lt;i&gt;VALUE_DESERIALIZER_CLASS_CONFIG&lt;/i&gt;&amp;nbsp;- deserializer implementation class for deserializing message values&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
-&lt;b&gt;&amp;nbsp;auto.offset.reset : &lt;/b&gt;this property tells kafka from which position on partition we want new consumer to start reading messages in case no other consumer from the group already read from it.&lt;/div&gt;
&lt;div&gt;
Default behaviour is to start reading from latest message existing on partitio at the time consumer connected Kafka cluster. In our case we set it to&amp;nbsp;&lt;i&gt;earliest,&lt;/i&gt; because we want to start processing messages from the&amp;nbsp;beginning of the partition.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
After instantiating KafkaConsumer object we must tell it from which topics we want to read the messages.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
And now we can start reading messages:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;while (!shutdown.get()) {&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ConsumerRecords&lt;string string=&quot;&quot;&gt; records = consumer.poll(1000);&lt;/string&gt;&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; records.forEach(record -&amp;gt; processMessage(record));&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here we have loop running until shutdown and in each iteration it reads messages using&amp;nbsp;&lt;span style=&quot;color: #0b5394; font-style: italic;&quot;&gt;consumer.poll() &lt;/span&gt;method. It receives timeout argument, and it will block current thread until messages are available or timeout expires, whatever comes first. In both cases this method will return&amp;nbsp;&lt;i style=&quot;color: #0b5394;&quot;&gt;ConsumerRecords &lt;/i&gt;object which is collection of&amp;nbsp;ConsumerRecord instances. Consumer record is key-value pair, representing message key and value and also containing some metadata of the message such as topic from which message was read, number of partition which hold this message and message offset (position) on it&#39;s partition.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Very important concept of consumer API are consumer groups. Consumer groups concept is Kafka&#39;s abstraction of queuing and publish-subscribe models. Two (or more) consumers from same group reading from same topic will never get same message (queuing model) but two (or more) consumers from different groups will (publish-subscribe model). This means that consumer group behaves like single logical consumer and specific consumers of the group (consumer nodes) are used for horizontal scaling of the logical consumer.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Since only one consumer from the group can read from &amp;nbsp;particular partition, in case when group has more consumers then topic has partitions, all extra consumers will be in kind of hot stand by - they will periodically ask Kafka for messages, but they will get empty record collection. If one of active consumers crashes, one of extra consumer nodes will start to receive messages exactly from the position crashed node stopped processing them.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
If there is single consumer node in a group reading from topic with two &amp;nbsp;or more partitions, this consumer will be getting messages from all partitions.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
By guaranteeing that only one consumer at the time can read from the partition, Kafka guarantees not just message delivery order but message processing order. &amp;nbsp;Note that this guarantee applies for partition scope, not for entire topic&amp;nbsp;&amp;nbsp;(with multiple partitions), but this should be enough since we can almost always group messages to partitions by some business property which is relevant for processing order. This is main purpose of message keys. Messages with same keys will end up on same partition , so if we use business property relevant for processing order as message key, we got things covered.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Yesterday Kafka 0.10 is released as part of &lt;a href=&quot;http://docs.confluent.io/3.0.0/release-notes.html&quot; target=&quot;_blank&quot;&gt;Confluent platform 3.0&amp;nbsp;&lt;/a&gt;&amp;nbsp;but since consumer API, which this post is focused on, had it major change in version 0.9 and not changed in 0.10, so everything said here still applies.&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Latest version of Kafka platform brings interesting things such as &amp;nbsp;&lt;b&gt;Streams library&lt;/b&gt; and&amp;nbsp;&lt;b&gt;Control Center&lt;/b&gt; and version 0.9 &amp;nbsp;brought S&lt;b&gt;ecurity&lt;/b&gt;&amp;nbsp;and&lt;b&gt;&amp;nbsp;Kafka Connect &lt;/b&gt;and I hope I will grab some time to blog about some of them soon.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/8406360422634563305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/8406360422634563305' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/8406360422634563305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/8406360422634563305'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2016/05/kafka-demo-at-javacro-conference.html' title='Kafka demo at JavaCro conference '/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb2i8p_SZFsKDCBCz0mFnzeJTlZXjY43uXCA2k5aTlIff41XszlgTebXIiwDtz3Bqsst-H86_wiBxwZYU2D1QwGOaTXRv7bhMHEgSp_LlrO0Y2pbG5ygPKC0Tp08DgDhDlssz-6UZN26E/s72-c/javacro_ib_kafka.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-5911002659120302132</id><published>2015-06-22T10:58:00.002+02:00</published><updated>2015-07-15T09:14:49.309+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="apache kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="apache kafka tutorial"/><title type='text'>Apache Kafka - First Contact</title><content type='html'>&lt;script src=&quot;https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js?skin=sons-of-obsidian&quot;&gt;&lt;/script&gt;

Finally I caught some time to dig into Kafka, a high-throughput distributed messaging system, as authors define it.&lt;br /&gt;
&lt;br /&gt;
Essentially, Kafka is publish-subscribe messaging system, it can be used for several &lt;a href=&quot;http://kafka.apache.org/documentation.html#uses&quot;&gt;use case scenarios&lt;/a&gt; but in this post we will focus on tradinional message broker use case.&lt;br /&gt;
Kafka stores every message on disk. Yet, it is very fast. If you are interested how is this achieved,&amp;nbsp;&lt;a href=&quot;http://kafka.apache.org/documentation.html#persistence&quot;&gt;read it later&lt;/a&gt;&amp;nbsp;:)&lt;br /&gt;
It is distributed by design - it is run as a cluster comprised of one or more servers each of which is called a broker.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
&lt;b&gt;Important concepts&lt;/b&gt;&lt;/h2&gt;
- Kafka stores messages in categories called topics.&lt;br /&gt;
- Topics consists of one or more &quot;partitions&quot;&lt;br /&gt;
- Each partition is an ordered, immutable sequence of messages that is continually appended to&lt;br /&gt;
- Processes that publish messages to Kafka are called producers&lt;br /&gt;
- Processes that subscribe to topics and fetch messages are called consumers&lt;br /&gt;
- Messages are not deleted after delivery, but after configured period of time.&lt;br /&gt;
&lt;br /&gt;
Partitions are replicated across Kafka cluster. Partition copies are distributed among multiple brokers but only one broker is &quot;partition leader&quot;, meaning that all writes and reads to that partition must be handled through that broker and other brokers are used for only redundancy. If partition leader broker crashes, Kafka will automatically elect another leader among brokers holding that partition copy.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
&lt;b&gt;Let the games begin!&lt;/b&gt;&lt;/h2&gt;
Now hat we know basic stuff, lets play.&lt;br /&gt;
In this &quot;how to&quot; I am using &lt;b&gt;Kafka 0.8.2.1&lt;/b&gt; so first step is to &lt;a href=&quot;https://www.apache.org/dyn/closer.cgi?path=/kafka/0.8.2.1/kafka_2.10-0.8.2.1.tgz&quot; target=&quot;_blank&quot;&gt;download it from this link&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
After download, unzip it, open terminal console and go to kafka directory you just extracted from downloaded archive.&lt;br /&gt;
&lt;br /&gt;
First, we must run&amp;nbsp;Apache ZooKeeper since Kafka uses it for managing cluster configuration information, bot no worries, it is included in Kafka distribution and you only need to run it :&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;bin/zookeeper-server-start.sh config/zookeeper.properties&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
Zookeeper should be started and produce some output with last line looking something like this:&lt;br /&gt;
&lt;span style=&quot;color: #666666;&quot;&gt;INFO binding to port 0.0.0.0/0.0.0.0:2181 (org.apache.zookeeper.server.NIOServerCnxnFactory)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Next step, open another terminal (unless you started zookeeper in background), and let&#39;s run Kafka.&lt;br /&gt;
One node will be enough for this test:&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #38761d;&quot;&gt;bin/kafka-server-start.sh config/server.properties&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
Hopefully everything went fine, and we have Kafka server running.&lt;br /&gt;
&lt;br /&gt;
Finally, open third terminal and create &amp;nbsp;topic for testing purposes:&lt;br /&gt;
&lt;span style=&quot;color: #38761d;&quot;&gt;bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 2 --topic my-test-topic&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
We set replication-factor argument to 1, which means we don&#39;t have replication (we only have one broker currently).&lt;br /&gt;
Also, we set number of partitions to 2, which will be important later, when we will be talking about consumers.&lt;br /&gt;
As last option we specify topic name: &quot;my-test-topic&quot;.&lt;br /&gt;
After we run this command, following output should appear:&lt;br /&gt;
&lt;span style=&quot;color: #666666;&quot;&gt;Created topic &quot;my-test-topic&quot;.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Now we have Kafka up and running! It is just one node (broker) but running more nodes is not complicated (&lt;a href=&quot;http://kafka.apache.org/documentation.html#quickstart&quot; target=&quot;_blank&quot;&gt;step 6 in kafka quickstart&lt;/a&gt;) and it&#39;s not so important for the purpose of this post, which is showing how to produce and consume some messages from Java application.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Java time&lt;/h2&gt;
We need following dependency for setting up our test application:&lt;br /&gt;
&lt;pre style=&quot;font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;&quot;&gt;&lt;code style=&quot;color: #cccccc; word-wrap: normal;&quot;&gt; &amp;lt;dependency&amp;gt;  
      &amp;lt;groupId&amp;gt;org.apache.kafka&amp;lt;/groupId&amp;gt;  
      &amp;lt;artifactId&amp;gt;kafka_2.11&amp;lt;/artifactId&amp;gt;  
      &amp;lt;version&amp;gt;0.8.2.1&amp;lt;/version&amp;gt;  
 &amp;lt;/dependency&amp;gt;  &lt;/code&gt;&lt;/pre&gt;
You can get complete example code at &lt;a href=&quot;https://github.com/beegor/kafka-test&quot; target=&quot;_blank&quot;&gt;my github repository&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
&lt;b&gt;Producer&lt;/b&gt;&lt;/h3&gt;
&lt;br /&gt;
When publishing message to Kafka cluster, producer must send it directly to partition leader, so it must know it&#39;s address. But have no fear, Producer API handles that part for you. All you have to do is provide addresses of one or more brokers (at least one but more is better for redundancy reasons) to producer configuration. Any broker can be queried for metadata containing information about topics and partitions, so API will use this list you provide to do so before really sending the message.&lt;br /&gt;
Let&#39;s &amp;nbsp;define producer properties:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;Properties props = new Properties();
props.put(&quot;metadata.broker.list&quot;, &quot;localhost:9092&quot;);
props.put(&quot;serializer.class&quot;, &quot;kafka.serializer.StringEncoder&quot;);
props.put(&quot;request.required.acks&quot;, &quot;1&quot;);
ProducerConfig config = new kafka.producer.ProducerConfig(props);&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #6fa8dc; font-family: Trebuchet MS, sans-serif;&quot;&gt;&lt;i&gt;metadata.broker.list&lt;/i&gt;&lt;/span&gt;&amp;nbsp;property, &amp;nbsp;addresses of one or more brokers for fetching metadata, &amp;nbsp;we have only one broker localhost:9092. For providing more broker addresses format is:&amp;nbsp;&lt;i&gt;host1:port1,host2:port2&lt;/i&gt;&lt;br /&gt;
&lt;span style=&quot;color: #6fa8dc; font-family: Trebuchet MS, sans-serif;&quot;&gt;&lt;i&gt;serializer.class&lt;/i&gt;&lt;/span&gt;&amp;nbsp;property, defines message serializer. We use built in&amp;nbsp;&lt;i&gt;StringEncoder &lt;/i&gt;class.&lt;br /&gt;
&lt;span style=&quot;color: #6fa8dc; font-family: Trebuchet MS, sans-serif;&quot;&gt;&lt;i&gt;request.required.acks&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Trebuchet MS, sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp;&lt;/span&gt;property,&lt;span style=&quot;font-family: Trebuchet MS, sans-serif; font-size: x-small;&quot;&gt;&amp;nbsp;&lt;/span&gt;1  means that the producer gets an acknowledgement after the leader replica has received the data, not waiting for other brokers to replicate the data. If we had more replicas we could ask for more then one acknowledgement, ensuring&amp;nbsp;better durability guarantees.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Configuration is ready, let&#39;s create producer:&lt;/div&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;Producer p = new Producer&lt;string string=&quot;&quot;&gt;(config);&lt;/string&gt;
&lt;/pre&gt;
and we can start sending messages:&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;KeyedMessage&lt;string string=&quot;&quot;&gt; keyedMessage = new KeyedMessage&lt;string string=&quot;&quot;&gt;(topic, key, message);
p.send(keyedMessage);
&lt;/string&gt;&lt;/string&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;div&gt;
OK, that will work, but... what is this &amp;nbsp;argument named &lt;i&gt;key&amp;nbsp;&lt;/i&gt;?&lt;br /&gt;
Remember when we created our topic in terminal console, we specified that we want 2 partitions for it. And now is time to explain why.&lt;br /&gt;
&lt;br /&gt;
Our goal is to have more then one consumer to consume messages from this topic. In Kafka, only one consumer can read messages from specific partition, so number of active consumers per topic is limited by the number of partitions in that topic. Having two partitions allow us to have two simultaneously active consumers.&lt;br /&gt;
&lt;br /&gt;
So far so good, we have two partitions, and now we want producer to distribute messages to both of them, right?&lt;br /&gt;
In order to do that, we must provide a message key (String) which will be used to determine target partition for each message. This is called semantic partitioning.&lt;br /&gt;
Default partition resolving strategy is implemented as &lt;i&gt;&lt;span style=&quot;color: #3d85c6;&quot;&gt;hash(key) % numberOfPartitions&lt;/span&gt;&lt;/i&gt; , meaning same key will always resolve same partition number (partitions inside topic are numbered as 0,1...P)&lt;br /&gt;
&lt;i&gt;KeyedMessage&lt;/i&gt;&lt;span style=&quot;font-size: 10px;&quot;&gt; &lt;/span&gt;can be instantiated without key : new KeyedMessage&amp;lt;&amp;gt;(topic, message) in which case Kafka should choose random partition (according to &amp;nbsp;documentation), but in my tests all messages went to first partition.&lt;br /&gt;
In our producer example we will generate keys also using modulo by&amp;nbsp;&lt;i&gt;&lt;span style=&quot;color: #3d85c6;&quot;&gt;numberOfPartitions&lt;/span&gt;&lt;span style=&quot;color: #0b5394;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;/i&gt;in order to achieve &quot;round-robin&quot; message distribution.&lt;br /&gt;
&lt;br /&gt;
Complete producer example:&lt;/div&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;package hr.ib.kafka.test;

import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;

import java.util.Properties;

public class ProducerTest {


    public ProducerTest(String topic, int partitionCount, int msgProduceDelay) {

        Properties props = new Properties();

        props.put(&quot;metadata.broker.list&quot;, &quot;localhost:9092&quot;);
        props.put(&quot;serializer.class&quot;, &quot;kafka.serializer.StringEncoder&quot;);
        props.put(&quot;request.required.acks&quot;, &quot;1&quot;);

        ProducerConfig config = new kafka.producer.ProducerConfig(props);
        Producer p = new Producer&lt;string string=&quot;&quot;&gt;(config);

        run(topic, partitionCount, msgProduceDelay, p);
    }


    private void run(String topic, int partitionCount, int msgProduceDelay, Producer p) {

        int i = 0;
        while(true) {
            String message = &quot;Message #&quot; + (i + 1);
            String key = &quot;&quot; + i % partitionCount;
            KeyedMessage&lt;string string=&quot;&quot;&gt; keyedMessage = new KeyedMessage&amp;lt;&amp;gt;(topic, key, message);
            p.send(keyedMessage);
            System.out.println(&quot;Sent message :&quot; + message);
            sleep(msgProduceDelay);
            i++;
        }
    }


    private void sleep(int millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        new ProducerTest(&quot;my-test-topic&quot;, 2, 500);
    }

}
&lt;/string&gt;&lt;/string&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;h3&gt;
Consumer&lt;/h3&gt;
&lt;br /&gt;
Before we dive into consumer code, we must know few things:&lt;br /&gt;
&lt;br /&gt;
1. In Kafka, brokers do not push messages to consumers, consumers pull them.&lt;br /&gt;
2. Kafka has &quot;Simple API&quot; (low level) and &quot;High level API&quot; for consumers.&lt;br /&gt;
3. Consumer group defines set of consumers for handling specific business task. We can think of consumer group as logical subscriber for specific topic.&lt;br /&gt;
4. For each partition, Kafka tracks &quot;consumer offset&quot; for each consumer group - a number of last &amp;nbsp;message in partition consumed by that consumer group.&lt;br /&gt;
&lt;br /&gt;
High level API handles offset tracking &amp;nbsp;automatically, but if you want to use some advanced features, like start processing messages from the beginning on consumer restart, you must use Simple API and handle offset tracking your self.&lt;br /&gt;
High level API is enough for most use cases, and in this example we will use it.&lt;br /&gt;
&lt;br /&gt;
As we already mentioned, one partition can be consumed by only one consumer at the same time.&lt;br /&gt;
Kafka implements this behavior &amp;nbsp;using&amp;nbsp;&lt;i&gt;KafkaStream -&amp;nbsp;&lt;/i&gt;only one stream per partition will be active in same time. If we try to open more streams then number of partitions in a topic, &quot;extra streams&quot; will be opened but no messages will be fed to them.&lt;br /&gt;
&lt;br /&gt;
First we have to create consumer connector:&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;String zooKeeper = &quot;localhost:2181&quot;;
String groupId = &quot;myApp&quot;;
String topic = &quot;my-test-topic&quot;; 

Properties props = new Properties();
props.put(&quot;zookeeper.connect&quot;, zooKeeper);
props.put(&quot;group.id&quot;, groupId);
props.put(&quot;zookeeper.session.timeout.ms&quot;, &quot;400&quot;);
props.put(&quot;zookeeper.sync.time.ms&quot;, &quot;200&quot;);
props.put(&quot;auto.commit.interval.ms&quot;, &quot;1000&quot;);

ConsumerConfig consumerConfig = new ConsumerConfig(props);

consumerConnector =  Consumer.createJavaConsumerConnector(consumerConfig);
&lt;/pre&gt;
&lt;br /&gt;
Consumer config is provided with zookeper location, &amp;nbsp;so it can get all Kafka cluster information it needs. And maybe most important parameter here -&amp;nbsp;&lt;span style=&quot;color: #6fa8dc;&quot;&gt;group.id&lt;/span&gt;, it is used to tell Kafka that this consumer is part of &quot;myApp&quot; consumer group.&lt;br /&gt;
We have established consumer connection, now we can get streams, and consume them.
We could fetch multiple streams and handle them in separate threads, but we will rather have each stream consumed in separate JVM process, so we will request only one stream via this consumer connection, and start multiple consumer instances in order to handle more streams.&lt;br /&gt;
This is how we fetch consumer streams from consumer connection:&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt; 

Map&amp;lt;String, Integer&amp;gt; topicCountMap = new HashMap&amp;lt;&amp;gt;();  
 topicCountMap.put(topic, new Integer(1));  
 Map&amp;lt;String, List&amp;lt;KafkaStream&amp;lt;byte[], byte[]&amp;gt;&amp;gt;&amp;gt; consumerMap = consumerConnector.createMessageStreams(topicCountMap);  
   
   
 List&amp;lt;KafkaStream&amp;lt;byte[], byte[]&amp;gt;&amp;gt; streams = consumerMap.get(topic);  
   
 for (KafkaStream&amp;lt;byte[], byte[]&amp;gt; stream : streams) {  
   StreamConsumer streamConsumer = new StreamConsumer(stream);  
   new Thread(streamConsumer).start();  
 }  

&lt;/pre&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #6fa8dc;&quot;&gt;topicCountMap&lt;/span&gt; is used to define which streams we want. We can ask for streams from multiple topics, and &amp;nbsp;specify how many stream for each topic we want. We just want one stream from our topic.&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
Stream consuming is pretty simple.&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt; 
 ConsumerIterator&amp;lt;byte[], byte[]&amp;gt; it = stream.iterator();  
 while (it.hasNext()) {  
    System.out.println(&quot;Consumed message: &quot; + new String(it.next().message()));  
 }  
&lt;/pre&gt;
&lt;br /&gt;
And here is complete consumer example:
&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt; 
package hr.ib.kafka.test;  
   
   
 import kafka.consumer.Consumer;  
 import kafka.consumer.ConsumerConfig;  
 import kafka.consumer.ConsumerIterator;  
 import kafka.consumer.KafkaStream;  
 import kafka.javaapi.consumer.ConsumerConnector;  
   
 import java.util.HashMap;  
 import java.util.List;  
 import java.util.Map;  
 import java.util.Properties;  
   
 public class ConsumerTest {  
   
   
   String zooKeeper = &quot;localhost:2181&quot;;  
   String groupId = &quot;myApp&quot;;  
   String topic = &quot;my-test-topic&quot;;  
   
   ConsumerConnector consumerConnector;  
   
   public ConsumerTest() {  
   
     Properties props = new Properties();  
     props.put(&quot;zookeeper.connect&quot;, zooKeeper);  
     props.put(&quot;group.id&quot;, groupId);  
     props.put(&quot;zookeeper.session.timeout.ms&quot;, &quot;400&quot;);  
     props.put(&quot;zookeeper.sync.time.ms&quot;, &quot;200&quot;);  
     props.put(&quot;auto.commit.interval.ms&quot;, &quot;1000&quot;);  
   
     ConsumerConfig consumerConfig = new ConsumerConfig(props);  
   
     consumerConnector = Consumer.createJavaConsumerConnector(consumerConfig);  
   
     Map&amp;lt;String, Integer&amp;gt; topicCountMap = new HashMap&amp;lt;&amp;gt;();  
     topicCountMap.put(topic, new Integer(1));  
     Map&amp;lt;String, List&amp;lt;KafkaStream&amp;lt;byte[], byte[]&amp;gt;&amp;gt;&amp;gt; consumerMap = consumerConnector.createMessageStreams(topicCountMap);  
   
   
     List&amp;lt;KafkaStream&amp;lt;byte[], byte[]&amp;gt;&amp;gt; streams = consumerMap.get(topic);  
   
     for (KafkaStream&amp;lt;byte[], byte[]&amp;gt; stream : streams) {  
       StreamConsumer streamConsumer = new StreamConsumer(stream);  
       new Thread(streamConsumer).start();  
     }  
   }  
   
   
   
   
   class StreamConsumer implements Runnable {  
   
     private KafkaStream stream;  
   
     public StreamConsumer(KafkaStream stream) {  
       this.stream = stream;  
     }  
   
     public void run() {  
       ConsumerIterator&amp;lt;byte[], byte[]&amp;gt; it = this.stream.iterator();  
       while (it.hasNext()) {  
         System.out.println(&quot;Consumed message: &quot; + new String(it.next().message()));  
       }  
     }  
   }  
   
   
   
   public static void main(String[] args) {  
     new ConsumerTest();  
   }  
   
   
 }  
&lt;/pre&gt;
&lt;br /&gt;
Now we can run one producer and &amp;nbsp;several consumers to see all this in action.&lt;br /&gt;
&lt;br /&gt;
I suggest following steps:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Run ProducerTest and leave it running.&lt;/li&gt;
&lt;li&gt;Run one ConsumerTest and observer output. You will notice it consumes all messages.&lt;/li&gt;
&lt;li&gt;Run second ConsumerTest and give it few seconds. Kafka will re-balance streams, and second consumer will start receiving messages (in my case even number messages), and first consumer will continue to consume only odd number messages.&lt;/li&gt;
&lt;li&gt;Start third ConsumerTest, and notice that it doesn&#39;t process any messages. It is because we only have two partitions, so third kafka stream will be empty. Leave it running anyway.&lt;/li&gt;
&lt;li&gt;Kill second consumer, and observe third one, it will soon start to process some messages. This is because Kafka re-balanced again after disconnection of second consumer and started to feed third consumer stream with messages.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;br /&gt;
And that&#39;s it.&lt;br /&gt;
&lt;br /&gt;
I will close with notice that Kafka 0.9 will &lt;a href=&quot;https://cwiki.apache.org/confluence/display/KAFKA/Consumer+Client+Re-Design&quot; target=&quot;_blank&quot;&gt;introduce new consumers API&lt;/a&gt;, so stay tuned for another &quot;how to&quot; &amp;nbsp;soon :)&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/5911002659120302132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/5911002659120302132' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/5911002659120302132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/5911002659120302132'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2015/06/apache-kafka-first-contact.html' title='Apache Kafka - First Contact'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-1784200327728535179</id><published>2013-10-06T17:14:00.000+02:00</published><updated>2015-06-12T09:28:12.773+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="#shiro"/><category scheme="http://www.blogger.com/atom/ns#" term="#spring"/><category scheme="http://www.blogger.com/atom/ns#" term="Apache Shiro"/><category scheme="http://www.blogger.com/atom/ns#" term="Apache Shiro Java config"/><category scheme="http://www.blogger.com/atom/ns#" term="Java config"/><category scheme="http://www.blogger.com/atom/ns#" term="Spring MVC"/><category scheme="http://www.blogger.com/atom/ns#" term="WebApplicationInitializer"/><title type='text'>Apache Shiro with Spring framework, Java config and WebApplicationInitializer</title><content type='html'>&lt;script src=&quot;https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js?skin=sons-of-obsidian&quot;&gt;&lt;/script&gt;


Recently I was adding &lt;a href=&quot;http://shiro.apache.org/&quot; target=&quot;_blank&quot;&gt;Apache Shiro&lt;/a&gt; security framework to Spring based web application which is using Java config and doesn&#39;t have xml configuration at all, not even web.xml&lt;br /&gt;
&lt;br /&gt;
Apache Shiro documentation is mostly using xml examples so it took some time to put it all together in Java config based application.&lt;br /&gt;
&lt;br /&gt;
Central part of Shiro security is &amp;nbsp;a realm. Here is how official Shiro documentation defines realms:&lt;br /&gt;
&lt;br /&gt;
&quot;&lt;i&gt;&lt;b&gt;A Realm is a component that can access application-specific security data such as users, roles, and permissions. The Realm translates this application-specific data into a format that Shiro understands so Shiro can in turn provide a single easy-to-understand &lt;a href=&quot;http://shiro.apache.org/subject.html&quot;&gt;Subject&lt;/a&gt; programming API no matter how many data sources exist or how application-specific your data might be&lt;/b&gt;&lt;/i&gt;.&quot;&lt;br /&gt;
&lt;br /&gt;
Shiro comes with number of&amp;nbsp;out-of-the-box Realm&lt;span style=&quot;font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif;&quot;&gt;&amp;nbsp;implementations that connects directly to database, to LDAP, etc, but in this example we will use custom Realm implementation since we want to access user data via our own user manager.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Helvetica Neue&#39;, Helvetica, Arial, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Helvetica, Arial, sans-serif;&quot;&gt;First, we have SecurityConfig. java where all security related beans are defined.&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;package com.xxx.yyy.config;

import com.xxx.yyy.security.CustomSecurityRealm;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

@Configuration
public class SecurityConfig {

    @Bean
    public CustomSecurityRealm customSecurityRealm(){
        return new CustomSecurityRealm();
    }

    @Bean
    public WebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(customSecurityRealm());
        return securityManager;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public MethodInvokingFactoryBean methodInvokingFactoryBean(){
        MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
        methodInvokingFactoryBean.setStaticMethod(&quot;org.apache.shiro.SecurityUtils.setSecurityManager&quot;);
        methodInvokingFactoryBean.setArguments(new Object[]{securityManager()});
        return methodInvokingFactoryBean;
    }

    @Bean
    @DependsOn(value=&quot;lifecycleBeanPostProcessor&quot;)
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        return new DefaultAdvisorAutoProxyCreator();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

}

&lt;/pre&gt;
First bean defined is our custom security realm implementation. We will take a look at it in a moment, but for now let just look where is it used. And we don&#39;t have to go far, it is used by shiro security manager defined as second bean in SecurityConfig.java. We use&amp;nbsp;DefaultWebSecurityManager since we plan to use Shiro for securing our applications URLs.&lt;br /&gt;
We just create an instance and inject our custom securtity realm bean to it.&lt;br /&gt;
&lt;br /&gt;
After that we have few Shiro beans and we just inject our security manager bean wherever required.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s look how our custom security realm implementation looks like.&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;package com.xxx.yyy.security;

import com.xxx.yyy.security.Role;
import com.xxx.yyy.security.Permission;
import com.xxx.yyy.User;
import com.xxx.yyy.UserManager;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

public class CustomSecurityRealm extends AuthorizingRealm {

    @Autowired
    private UserManager userManager;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        Set&lt;string&gt; roles = new HashSet&amp;lt;&amp;gt;();
        Set&lt;org .apache.shiro.authz.permission=&quot;&quot;&gt; permissions = new HashSet&amp;lt;&amp;gt;();

        Collection&lt;user&gt; principalsList = principals.byType(User.class);
        for (User user : principalsList) {
            for (Role role : user.getRoles()) {
                roles.add(role.getName());
                for (Iterator&lt;permission&gt; iterator = role.getPermissions().iterator(); iterator.hasNext(); ) {
                    Permission permission = iterator.next();
                    permissions.add(new WildcardPermission(permission.name()));
                }
            }
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        info.setRoles(roles);
        info.setObjectPermissions(permissions);

        return info;
    }

     @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        UsernamePasswordToken upat = (UsernamePasswordToken) token;
        User user = userManager.getByUsername(upat.getUsername());
        if(user != null &amp;amp;&amp;amp; user.getPassword().equals(new String(upat.getPassword()))) {
            return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
        }
        else {
            throw new AuthenticationException(&quot;Invalid username/password combination!&quot;);
        }
    }
}
&lt;/permission&gt;&lt;/user&gt;&lt;/org&gt;&lt;/string&gt;&lt;/pre&gt;
&lt;br /&gt;
Our security &amp;nbsp;realm implementation will be used both for authentication and authorization so we extend &amp;nbsp;AuthorizingRealm which extends&amp;nbsp;AuthenticatingRealm.&lt;br /&gt;
Autowired UserManager is our application service for accessing users and their roles and permissions.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;doGetAuthenticationInfo&lt;/b&gt; method is used to authenticate user, and it has one argument - &lt;i&gt;AuthenticationToken&lt;/i&gt; which holds username and password entered by user in login form.&lt;br /&gt;
Inside this method we check if user for given username exists and if password matches the password enetered by user. If those conditions are satisfied, we return&amp;nbsp;&lt;i&gt;AuthenticationInfo&lt;/i&gt;&amp;nbsp;object with our user object as principal. We use Shiro&#39;s &lt;i&gt;SimpleAuthenticationInfo&lt;/i&gt; implementation of &lt;i&gt;AuthenticationInfo&lt;/i&gt; interface.&lt;br /&gt;
If user doesn&#39;t exist or password doesn&#39;t match we throw Authentication exception.&lt;br /&gt;
This is very simple example, in real project we will probably use Shiro&#39;s&amp;nbsp;HashedCredentialsMatcher for checking username/password combination since we probably want to use encoded passwords.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;doGetAuthorizationInfo&lt;/b&gt; method is used by Shiro to get roles and permissions for specific principal(s) so it has&amp;nbsp;&lt;i&gt;PrincipalCollection&lt;/i&gt; as argument. For every principal in given collection (usually there will be only one) we will get roles and permissions and set them to&amp;nbsp;&lt;i&gt;AuthorizationInfo&lt;/i&gt; which will be returned by this method. We use Shiro&#39;s &lt;i&gt;SimpleAuthorizationInfo&lt;/i&gt; implementation for this purpose. The code should be pretty self-explanatory.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now that we have our basic security infrastructure defined, we need to integrate it with our web application.&lt;/div&gt;
&lt;div&gt;
In order to protect urls we need to add Shiro filter to our web app descriptor. &amp;nbsp;As I mentioned in the beginning of this post, we don&#39;t use web.xml but instead we have&amp;nbsp;&lt;i&gt;&lt;a href=&quot;http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/WebApplicationInitializer.html&quot; target=&quot;_blank&quot;&gt;WebApplicationInitializer&lt;/a&gt;&lt;/i&gt;.&lt;/div&gt;
here is how it looks like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;package com.xxx.yyy;

import com.xxx.yyy.config.DataConfig;
import com.xxx.yyy.config.SecurityConfig;
import com.xxx.yyy.config.WebConfig;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

public class WebInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {

        // Create the &#39;root&#39; Spring application context
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register( DataConfig.class, SecurityConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));


        // Create the dispatcher servlet&#39;s Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
        dispatcherContext.setServletContext(container);
        dispatcherContext.setParent(rootContext);
        dispatcherContext.register(WebConfig.class);


        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet(&quot;dispatcher&quot;, new DispatcherServlet(dispatcherContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping(&quot;/&quot;);


        container.addFilter(&quot;shiroFilter&quot;, new DelegatingFilterProxy(&quot;shiroFilterBean&quot;, dispatcherContext))
                           .addMappingForUrlPatterns(null, false, &quot;/*&quot;);

    }
}
&lt;/pre&gt;
The code speaks for itself. We have root context with DataConfig (which contains JPA configuration, but this is not relevant for this story) and our SecurityConfig explained earlier.&lt;br /&gt;
&lt;br /&gt;
In order to configure our Spring MVC &amp;nbsp;we added dispatcher context,and registered WebConfig class which contains required beans.&lt;br /&gt;
&lt;br /&gt;
Last bean is most relevant since it defines Shiro filter which is configured to intercept all URLs.&lt;br /&gt;
We use&amp;nbsp;&lt;i&gt;DelegatingFilterProxy&lt;/i&gt; as filter implementation, and we provide &quot;shiroFilterBean&quot; for bean name.&lt;br /&gt;
This bean is defined in our WebConfig class, so let&#39;s take a look at it:

&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-java&quot; style=&quot;font-size: 10px;&quot;&gt;package com.xxx.yyy;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {&quot;com.xxx.yyy.web&quot;})
public class WebConfig extends WebMvcConfigurerAdapter {


    @Autowired
    private WebSecurityManager securityManager;


    @Bean
    public VelocityConfigurer velocityConfig() {
        VelocityConfigurer configurer = new VelocityConfigurer();
        configurer.setResourceLoaderPath(&quot;/WEB-INF/templates&quot;);
        Properties props = new Properties();
        props.put(&quot;output.encoding&quot;, &quot;UTF-8&quot;);
        props.put(&quot;input.encoding&quot;, &quot;UTF-8&quot;);
        configurer.setVelocityProperties(props);
        return configurer;
    }

    @Bean
    public VelocityViewResolver viewResolver() {
        VelocityViewResolver resolver = new VelocityLayoutViewResolver();
        resolver.setExposeSpringMacroHelpers(true);
        resolver.setContentType(&quot;text/html;charset=UTF-8&quot;);
        resolver.setSuffix(&quot;.vm&quot;);
        return resolver;
    }

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames(&quot;/WEB-INF/localization/messages&quot;);
        messageSource.setDefaultEncoding(&quot;UTF-8&quot;);
        messageSource.setCacheSeconds(10);
        return messageSource;
    }

    @Bean
    public LocaleResolver localeResolver() {
        CookieLocaleResolver localeResolver = new CookieLocaleResolver();
        localeResolver.setCookieName(&quot;LOCALE&quot;);
        return localeResolver;
    }


    @Bean
    public ShiroFilterFactoryBean shiroFilterBean(){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        Map&amp;lt;String, String&amp;gt; definitionsMap = new HashMap&amp;lt;&amp;gt;();
        definitionsMap.put(&quot;/login.jsp&quot;, &quot;authc&quot;);
        definitionsMap.put(&quot;/admin/**&quot;, &quot;authc, roles[admin]&quot;);
        definitionsMap.put(&quot;/**&quot;, &quot;authc&quot;);
        shiroFilter.setFilterChainDefinitionMap(definitionsMap);
        shiroFilter.setLoginUrl(&quot;/login.jsp&quot;);
        shiroFilter.setSecurityManager(securityManager);
        return shiroFilter;
    }
}

&lt;/pre&gt;
&lt;br /&gt;
This is typical java config based Spring MVC configuration.&lt;br /&gt;
Beside usual Spring MVC beans, we added &lt;i&gt;ShiroFilterFactoryBean&lt;/i&gt; (at the end) which will be referenced &amp;nbsp;from our&amp;nbsp;&lt;i&gt;WebApplicationInitializer&lt;/i&gt; , remember ?&lt;br /&gt;
&lt;i&gt;ShiroFilterFactoryBean&lt;/i&gt; requires &lt;i&gt;WebSecurityManager&lt;/i&gt; and since we defined it in SecurityConfig.java , all we need to do here is to autowire it to private field (line 12) and inject it to&amp;nbsp;shiroFilterBean (line 60)&lt;br /&gt;
&lt;br /&gt;
In between we just have velocity template engine configuration beans as well as localization beans which are not relevant for security framework.&lt;br /&gt;
&lt;br /&gt;
Now, when user attempts to &amp;nbsp;access any application URL, Shiro filter will intercept it, and delegate security checking to shiroFilterBean which will use&amp;nbsp;securityManager bean to determine if the user has right to access this specific URL.&lt;br /&gt;
If user is not authenticated yet, Shiro filter will redirect user to login page. Here is simple example of login.jsp:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;prettyprint linenums lang-html&quot; style=&quot;font-size: 10px;&quot;&gt;&amp;lt;form action=&quot;&quot; method=&quot;post&quot; name=&quot;loginform&quot;&amp;gt;
  &amp;lt;table align=&quot;left&quot; border=&quot;0&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot;&amp;gt;
    &amp;lt;tr&amp;gt;
 &amp;lt;td&amp;gt;Username:&amp;lt;/td&amp;gt;
 &amp;lt;td&amp;gt;&amp;lt;input maxlength=&quot;30&quot; name=&quot;username&quot; type=&quot;text&quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
 &amp;lt;td&amp;gt;Password:&amp;lt;/td&amp;gt;
 &amp;lt;td&amp;gt;&amp;lt;input maxlength=&quot;30&quot; name=&quot;password&quot; type=&quot;password&quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
 &amp;lt;td align=&quot;left&quot; colspan=&quot;2&quot;&amp;gt;
   &amp;lt;input name=&quot;rememberMe&quot; type=&quot;checkbox&quot; /&amp;gt;&amp;lt;span style=&quot;font-size: x-small;&quot;&amp;gt;Remember Me&amp;lt;/span&amp;gt;
 &amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
    &amp;lt;tr&amp;gt;
 &amp;lt;td align=&quot;right&quot; colspan=&quot;2&quot;&amp;gt;&amp;lt;input name=&quot;submit&quot; type=&quot;submit&quot; value=&quot;Login&quot; /&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;/tr&amp;gt;
  &amp;lt;/table&amp;gt;
&amp;lt;/form&amp;gt;

&lt;/pre&gt;
&lt;br /&gt;
And that&#39;s it... we have basic Shiro security setup. The way how application persists users, their roles and permission is application specific. All that Shiro has to know about this will get it from our security realm implementation.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;UPDATE: Added /login.jsp to&amp;nbsp;&lt;span style=&quot;font-size: 10px;&quot;&gt;&amp;nbsp;&lt;/span&gt;ShiroFilterFactoryBean&amp;nbsp;definitionsMap. &amp;nbsp;Without it Shiro will not handle login form submit correctly. &amp;nbsp;Although it looks like we are restricting anonymous access to it, Shiro will know that it should allow it.&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;UPDATE 2: Added imports to code&amp;nbsp;snippets&amp;nbsp;.&lt;/b&gt;&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/1784200327728535179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/1784200327728535179' title='26 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/1784200327728535179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/1784200327728535179'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2013/10/apache-shiro-with-spring-framework-java.html' title='Apache Shiro with Spring framework, Java config and WebApplicationInitializer'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>26</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-3723127161759944942</id><published>2013-09-15T20:44:00.001+02:00</published><updated>2013-10-02T16:02:09.607+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="sencha android"/><title type='text'>Building native android app with Sencha Cmd on linux</title><content type='html'>Recently I started to work on project with &amp;nbsp;Sencha Touch framework (client requirement) and my first task &amp;nbsp;was to build simple screen with some GUI components and make it run on android as native app.&lt;br /&gt;
&lt;br /&gt;
I was required to use Sencha Architect for development and app building but since I use Linux &amp;nbsp;and Sencha Architect supports app packaging only on windows and Mac, I had to use Sencha Cmd utility for building native app.&lt;br /&gt;
&lt;br /&gt;
Before I go any further let me throw some info on my development environment:&lt;br /&gt;
&lt;br /&gt;
OS: Ubuntu 13.04&lt;br /&gt;
Java 1.7&lt;br /&gt;
Ruby 1.9.3&lt;br /&gt;
Sencha Arcitect 2.2.2 build 991&lt;br /&gt;
Sencha Cmd&amp;nbsp;v3.1.3.372&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
After reading quick start docs it all looked easy, but as it often happens when using new tools, I quickly run into some frustrating problems.&lt;br /&gt;
&lt;br /&gt;
I made simple app, tested it in browser, and I thought I was ready to package it for android. Before building native app, I configured packager file (which contains mobile app configuration, such as app name, package id, android API level, android sdk path etc...)&lt;br /&gt;
&lt;br /&gt;
Fired up terminal, navigated to project folder, and as Sencha documantation instructs, I run build command :&amp;nbsp;&lt;i&gt;&lt;span style=&quot;color: #ea9999;&quot;&gt;sencha app build native&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
And... after few seconds my apk is generated... NOOOT!&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;iframe allowfullscreen=&#39;allowfullscreen&#39; webkitallowfullscreen=&#39;webkitallowfullscreen&#39; mozallowfullscreen=&#39;mozallowfullscreen&#39; width=&#39;320&#39; height=&#39;266&#39; src=&#39;https://www.youtube.com/embed/qoethxOp5Kg?feature=player_embedded&#39; frameborder=&#39;0&#39;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
First bump, tool complained that it misses nimblekit.jar.&lt;br /&gt;
&lt;br /&gt;
I haven&#39;t found anything about this in official Sencha documentation, but some people out there on the net &amp;nbsp;experienced same problem and found the solution: copy st-res folder from &lt;i&gt;&lt;span style=&quot;color: #ea9999;&quot;&gt;$sencha_cmd_install/stbuild&lt;/span&gt;&lt;/i&gt; to your project folder.&lt;br /&gt;
I am not sure why Sencha Cmd doesn&#39;t know where to find st-res folder, documentation doesn&#39;t says anything about it (AFAIK). Same problem happens on windows. However, copying st-res folder solves the problem both on linux and windows.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio8hRtwO_oPf_rUs0h6QRvXTqTDEz9VROUHNPlDIYLxaSb7ExN058OP5UkJ0MgOYG718puhT1SKFaUZVET2mSspmj2M-LuRWzvn_J7dxbNEoDHSUKlAwGexC3J1-T_JF99AB_rfkmyiI0/s1600/snapshot1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio8hRtwO_oPf_rUs0h6QRvXTqTDEz9VROUHNPlDIYLxaSb7ExN058OP5UkJ0MgOYG718puhT1SKFaUZVET2mSspmj2M-LuRWzvn_J7dxbNEoDHSUKlAwGexC3J1-T_JF99AB_rfkmyiI0/s400/snapshot1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
OK, problem solved, let&#39;s continue...&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;span style=&quot;color: #ea9999;&quot;&gt;sencha app build native ...&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&amp;nbsp;and... after few seconds my apk is generated... &amp;nbsp;NOOOT!&lt;br /&gt;
&lt;br /&gt;
Second problem caused me saying &quot;WTF&quot; quite a few times.&lt;br /&gt;
&lt;br /&gt;
Command runs for a long time (minute or two) and then reports &quot;Zip add failed&quot; error on Icon.png file.&lt;br /&gt;
Since I haven&#39;t change icon configuration in packager component, I expected default icons to be used.&lt;br /&gt;
After unsuccessful&amp;nbsp;googling&amp;nbsp;for the problem and running the command few times, I noticed that Icon.png file in build/native/res/drawable-mdpi grows up to 2 G !!! Same goes for drawable-mdpi.&lt;br /&gt;
But in drawable-hdpi , Icon size is normal, about 3.5 K. &amp;nbsp;I checked packager icon config and realized that default icon config doesn&#39;t define low dpi and medium dpi at all.&lt;br /&gt;
On windows this problem doesn&#39;t appear event though icon config is same.&lt;br /&gt;
Obviously, there is some bug on linux version of Sencha Cmd that causes the problem.&lt;br /&gt;
I managed to solve the problem by defining low and medium dpi icons (36 and 48 px).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Since I &#39;m pretty new to Sencha, it&#39;s probably to early to judge, but my first impression is not very positive.&lt;br /&gt;
Besides the problems I described what&#39;s bothering me &amp;nbsp;the most is that Sencha Architect doesn&#39;t have code completion.&lt;br /&gt;
&lt;br /&gt;
Feel free to throw a comment, especially if you had similar experiences with Sencha.</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/3723127161759944942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/3723127161759944942' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/3723127161759944942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/3723127161759944942'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2013/09/building-native-android-app-with-sencha.html' title='Building native android app with Sencha Cmd on linux'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio8hRtwO_oPf_rUs0h6QRvXTqTDEz9VROUHNPlDIYLxaSb7ExN058OP5UkJ0MgOYG718puhT1SKFaUZVET2mSspmj2M-LuRWzvn_J7dxbNEoDHSUKlAwGexC3J1-T_JF99AB_rfkmyiI0/s72-c/snapshot1.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-4023471270919768896</id><published>2013-08-18T13:45:00.000+02:00</published><updated>2013-09-19T14:08:38.083+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="3d"/><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="game development"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="rajawali"/><title type='text'>Developing 3d game for Android - part 2</title><content type='html'>Well, it is done!&lt;br /&gt;
&lt;br /&gt;
I finished version 1.0 of my 3D space arcade game based on &amp;nbsp;Rajawali framework and published it on &amp;nbsp;Google Play.&lt;br /&gt;
&lt;br /&gt;
You can check it out here:&amp;nbsp;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.mabuga.gravity.android.before4&amp;amp;hl=en&quot;&gt;https://play.google.com/store/apps/details?id=com.mabuga.gravity.android.before4&amp;amp;hl=en&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
And here is gameplay video on youtube:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;object class=&quot;BLOGGER-youtube-video&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot; codebase=&quot;http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0&quot; data-thumbnail-src=&quot;http://i1.ytimg.com/vi/qZb4_5uWf-w/0.jpg&quot; height=&quot;266&quot; width=&quot;320&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/qZb4_5uWf-w?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; /&gt;&lt;param name=&quot;bgcolor&quot; value=&quot;#FFFFFF&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;embed width=&quot;320&quot; height=&quot;266&quot;  src=&quot;http://www.youtube.com/v/qZb4_5uWf-w?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I enjoyed developing with Rajawali, it was very fun and the issues I run into were not critical.&lt;br /&gt;
Issue that I spent most time dealing with is rendering explosions. I wanted to use simple animated sprites for explosions and Rajawali supports that via Particle primitive. Basically, you set spritesheet texture to a Particle, define how many tiles spritesheet has, and Rajawali shader will render the particle using given spritesheet creating animation from it&#39;s tiles.&lt;br /&gt;
&lt;br /&gt;
What I wanted is just one big animated sprite to render explosion. And that was where the problem appears - the size of single particle. &amp;nbsp;Actually there are two problems related to particle size.&lt;br /&gt;
&lt;br /&gt;
1. There is a bug in Particle code that is causing particle look smaller as as the distance from world origin gets bigger, regardless of camera position.&lt;br /&gt;
&lt;br /&gt;
2. Particle is rendered as textured point and unfortunately OpenGL implementations limit the size of the rendered point. Even worse, different implementation has different values for point size limit. OpenGL specification doesn&#39;t guarantee point size bigger then 1 px.&lt;br /&gt;
&lt;br /&gt;
My workaround for first problem was to update particle code (GL shader and java) to fit my needs. Unfortunately, my solution did not solve the bug in generic way (since the problem is not just bug in calculation but conceptual as well) so I could not commit it back to the project.&lt;br /&gt;
&lt;br /&gt;
Second problem actually can not be really solved since it it hardware specific, so I just accepted imposed point size limit. Quick test on few devices I own showed me that point size limit is around 100 px on my HTC Explorer with 480x320 px screen and around 500 px on my Samsung Galaxy Tab 2 with 1280x800 px screen. That was ok for my explosions, however, there are probably devices with big screen and small point size limit and my explosions probably look bad on those.&lt;br /&gt;
&lt;br /&gt;
Also, I experienced some weird rendering issues when returning from RajawaliActivity with RajawaliRendered to normal Activity, but that was solved by setting android:hardwareAccellerated to false on activity elements in android manifest.&lt;br /&gt;
&lt;br /&gt;
So, there were actually very few problems with Rajawali framework.&lt;br /&gt;
Besides the issues, I would like to share some thoughts about challenges of optimizing the game for low CPU powered devices.&lt;br /&gt;
&lt;br /&gt;
Crucial part of almost any game is collision detection. Rajawali already has built in collision detection features, but checking collisions too often can have significant CPU cost causing glitches in gameplay.&lt;br /&gt;
In every frame (about 30 times per second) we have to check collision of every moving object with all other objects on the scene. Let&#39;s say that we have 30 moving objects (ships + bullets) and about 20 - 30 static objects (meteors) on the scene at the same time, this means we have to handle ~ 30 * 50 = 1500 checks per frame which makes 45 000 per second. And that&#39;s a lot.&lt;br /&gt;
In order to minimize number of collision checks per frame, I divided game space into &quot;sectors&quot;. For static objects I only calculate in which sector they are in game init phase, and for moving objects I had to calculate in which sector they are every time they move.&lt;br /&gt;
Also, I added global sector map that maps sector name to a list of objects currently in that sector. This map is also updated on every object sector calculation.&lt;br /&gt;
So, now for every moving object we only need to check collisions with objects currently in same sector , and this is usually 0-5 objects. This reduces CPU usage big time. This way number of collision checks doesn&#39;t increase at all if we add more static (non moving) objects.&lt;br /&gt;
&lt;br /&gt;
Another thing I optimized in order to achieve better game performance is to handle object creation little bit smarter then just create them when ever I need them. Actually, I recycle them.&lt;br /&gt;
Whenever new bullet is fired or new ship should appear, it should be added to scene, and whenever ship is destroyed or bullet hits something, it should be removed from the scene. &amp;nbsp;But adding and removing new objects can also be costly, especially if it happens often. If we instantiate new bullet every time ship fires, we spend CPU cycles on initiation of the bullet. After that we have to add it to a scene (renderer), and this also takes some CPU time since renderer must register new object to it&#39;s list of objects in synchronized way. Rajawally uses synchronized &quot;copy on write&quot; list for this purpose.&lt;br /&gt;
&lt;br /&gt;
So, instead of creating and destroying new objects all the time, I used well known technique called &quot;object pooling&quot; . It boils down to creating certain number of objects and store them in a pool (a list or a map) , then take it from that pool when we need new object and return it when the object should be destroyed/removed.&lt;br /&gt;
In my case, I had two different pools, one for bullets, another for explosions. Using two pools for specific object types instead using one generic pool also makes things faster since we don&#39;t have to do any type checking.&lt;br /&gt;
If new object is required and the pool is empty, we simple create new object and add it to the pool, so our pool will grow depending on demands.&lt;br /&gt;
&lt;br /&gt;
When object need to be removed from the scene, I don&#39;t actually remove it, I just hide it by setting visibility to false and by setting its position far out of the camera view. I also remove it from my internal list of movable objects, so I don&#39;t move it or check collisions for it while it is in the pool (kind of object passivation).&lt;br /&gt;
&lt;br /&gt;
When taken from the pool, object is set to visible, its position/rotation is updated as needed, and it is added to movable objects list, so it can be managed by game logic (moving and collision checking).&lt;br /&gt;
And that&#39;s it. Simple, but effective.&lt;br /&gt;
&lt;br /&gt;
OpenGL handles rendering in most optimized way it can, and besides the few tricks described above there are several other things developer can do to make the game run smooth:&lt;br /&gt;
- use low poly 3D models&lt;br /&gt;
- keep number of objects on the scene as low as you can&lt;br /&gt;
- keep objects static (non movable) whenever possible&lt;br /&gt;
&lt;br /&gt;
I covered some basic and common things related to game optimization, but every game is specific and it has specific things that can be optimized.</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/4023471270919768896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/4023471270919768896' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/4023471270919768896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/4023471270919768896'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2013/08/developing-3d-game-for-android-part-2.html' title='Developing 3d game for Android - part 2'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-8999540647449312705</id><published>2013-07-05T13:36:00.001+02:00</published><updated>2013-09-19T14:08:15.314+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="3d"/><category scheme="http://www.blogger.com/atom/ns#" term="android rajawali"/><category scheme="http://www.blogger.com/atom/ns#" term="game development"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><title type='text'>Developing 3d game for Android</title><content type='html'>To develop real 3D game is not trivial task no matter what platform you target.&lt;br /&gt;
&lt;br /&gt;
Five or six &amp;nbsp;years ago I was experimenting with &lt;a href=&quot;https://jogamp.org/jogl/www/&quot; target=&quot;_blank&quot;&gt;JOGL - Java Binding for the OpenGL API&lt;/a&gt;&amp;nbsp;trying to develop 3D game in java for PC.&lt;br /&gt;
In that time it was common opinion that 3D games can only be devleoped with C++ since java is too slow. Even then that was not true. JOGL delegates all rendering to OpenGL , and in initialization phase you can create complex objects in OpenGL memory so later you can reference it from java and give short instructions to OpenGL in order to move or rotate that object. That means that java only have to manage positions and rotations of the objects, check collisions and of course game logic.&lt;br /&gt;
&lt;br /&gt;
Since rendering is most demanding part of 3D game and it is handled by OpenGL , &amp;nbsp;C++ being faster then java doesn&#39;t matter so much. Of course , in Java you will probably have to optimize more, but it is definitely fast enough.&lt;br /&gt;
&lt;br /&gt;
I was very happy how my experiment turned out. Although I never finished and published the game, I managed to make nice little space combat with real LAN multiplayer so players could fight in space. It had laser guns, missiles that follow the targets, radar, etc. It was running smooth both on Windows and Linux.&lt;br /&gt;
&lt;br /&gt;
Today, even cheap smartphones (like my HTC Explorer) have similar CPU power and memory my PC had at time I was playing with JOGL.&lt;br /&gt;
&lt;br /&gt;
Smartphones support &lt;a href=&quot;http://www.khronos.org/opengles/&quot; target=&quot;_blank&quot;&gt;OpenGLES - The Standard for Embedded Accelerated 3D Graphics&lt;/a&gt;. Most phones support OpenGL ES 2.0, only older models still use OpenGL ES 1.x.&lt;br /&gt;
&lt;br /&gt;
Working with JOGL, developer actually has to know much about OpenGL since JOGL is not a 3D engine, it is just a bridge between Java and OpenGL which allows us to call OpenGL commands from Java code.&lt;br /&gt;
&lt;br /&gt;
In recent years several good 3D libraries emegred, making 3D apps development much easier. Since they manage low level OpenGL calls, you can focus more on your game logic.&lt;br /&gt;
&lt;br /&gt;
There is a great OpenGL ES 2.0 based 3D engine for Android platform called&amp;nbsp;&lt;a href=&quot;https://github.com/MasDennis/Rajawali&quot; target=&quot;_blank&quot;&gt;Rajawali&lt;/a&gt;,&amp;nbsp;developed by Dennis Ippel (great job Dennis). There is also &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.monyetmabuk.rajawali.tutorials&quot; target=&quot;_blank&quot;&gt;Android Demo app&lt;/a&gt; that demonstrate Rajawali engine features.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Basic feature that every 3D engine provides is loading external 3D model, adding it to 3D scene and manipulating it&#39;s position and rotation. Most 3D engines provide much more features including collision checking, physics, lighting, various visual effects, etc.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Rajawali&#39;s set of features amazed me so I decided to try it out by &amp;nbsp;making simple 3D game that focuses on playability &amp;nbsp;rather then on visual attraction. As a kid a loved games like &lt;a href=&quot;http://www.galagagame.net/galaga.php&quot; target=&quot;_blank&quot;&gt;Galaga&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Phoenix_(video_game)&quot; target=&quot;_blank&quot;&gt;Phoenix&lt;/a&gt;&amp;nbsp;because they were dynamic and addictive. My goal is to achieve similar gameplay dynamic in 3D world. &amp;nbsp;Although I limited ships freedom to move to a plane (can&#39;t go up or down), 3D perspective gives me more &quot;space&quot; (player can see distant enemy ships much earlier that it would be possible if the view was from above) and of course 3D models of ships and meteors look more realistic then it can be achieved in 2D.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here are first screenshots of the game :&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsD52K0zCgHHrcuGsK-Gb2e6Iag-069Xm5t4z0dqRNQMFquu3XHkFin9jLEOT8mE1VdVKM1i1PO7g7TuKSEO6GhpqblyA_CpXRrr4wBIzpvEm-CMMB3rM_Gi-l7RBCubx6Hgf8To6RBnc/s480/device-2013-07-05-124657.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;265&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsD52K0zCgHHrcuGsK-Gb2e6Iag-069Xm5t4z0dqRNQMFquu3XHkFin9jLEOT8mE1VdVKM1i1PO7g7TuKSEO6GhpqblyA_CpXRrr4wBIzpvEm-CMMB3rM_Gi-l7RBCubx6Hgf8To6RBnc/s400/device-2013-07-05-124657.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_C3CVmU2sQGdrex2p46Fm0PCzkeVjLrM_iK23RW70pz5pWgtC4Mu3LQ-3nb6OprzRLAf_SsDpgh246ZoFgm6wtIoXLH4PEJkPylWT7zNLT97uJSFnQZ4hZt9IGHiTjJWm4jw3KVCgk8Y/s480/device-2013-07-05-124815.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;266&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_C3CVmU2sQGdrex2p46Fm0PCzkeVjLrM_iK23RW70pz5pWgtC4Mu3LQ-3nb6OprzRLAf_SsDpgh246ZoFgm6wtIoXLH4PEJkPylWT7zNLT97uJSFnQZ4hZt9IGHiTjJWm4jw3KVCgk8Y/s400/device-2013-07-05-124815.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9GF94ln7jzKc6r46iRI7FINmy-zEiS2q43zy2076dw23bKibWMApHiXdoSoxwY_DSg54dVeKnO7bv7vv9scheb5lJ1u1zIStr_m7RP1dW4_xxEszbH07A7MayKmAxo2apOz97YczqTTM/s480/device-2013-07-05-124903.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;266&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9GF94ln7jzKc6r46iRI7FINmy-zEiS2q43zy2076dw23bKibWMApHiXdoSoxwY_DSg54dVeKnO7bv7vv9scheb5lJ1u1zIStr_m7RP1dW4_xxEszbH07A7MayKmAxo2apOz97YczqTTM/s400/device-2013-07-05-124903.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
So far everything works fine on HTC Explorer (Android 2.3.5) and HTC Desire C (Android 4.0).&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
I&#39;ll keep you posted about my progress here.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/8999540647449312705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/8999540647449312705' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/8999540647449312705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/8999540647449312705'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2013/07/developing-3d-game-for-android.html' title='Developing 3d game for Android'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsD52K0zCgHHrcuGsK-Gb2e6Iag-069Xm5t4z0dqRNQMFquu3XHkFin9jLEOT8mE1VdVKM1i1PO7g7TuKSEO6GhpqblyA_CpXRrr4wBIzpvEm-CMMB3rM_Gi-l7RBCubx6Hgf8To6RBnc/s72-c/device-2013-07-05-124657.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-7341463062396741671</id><published>2013-06-23T17:35:00.001+02:00</published><updated>2013-09-19T14:09:21.660+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="kotlin"/><category scheme="http://www.blogger.com/atom/ns#" term="programming language"/><title type='text'>Developing android apps with Kotlin</title><content type='html'>For those who haven&#39;t heard yet, &lt;a href=&quot;http://kotlin.jetbrains.org/&quot; target=&quot;_blank&quot;&gt;Kotlin&lt;/a&gt; is new JVM language developed by &lt;a href=&quot;http://www.jetbrains.com/&quot; target=&quot;_blank&quot;&gt;JetBrains&lt;/a&gt;, creators of &lt;a href=&quot;http://www.jetbrains.com/idea/&quot; target=&quot;_blank&quot;&gt;IntelliJ IDEA&lt;/a&gt;, which many people consider the best&amp;nbsp;java IDE.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Kotlin is still in development, beta should be released in following months, according to &lt;a href=&quot;http://devnet.jetbrains.com/community/kotlin&quot; target=&quot;_blank&quot;&gt;Kotlin forum&lt;/a&gt;, but it is already stable enough to do some real work in it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Being java programmer for a long time, I always liked it for simplicity of the language itself, stability, large ecosystem of frameworks and libraries, cross-platform support etc...&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
But sometimes I missed few things that other languages have and Java doesn&#39;t. &amp;nbsp;Mostly things that would boost my productivity and make me write less code that is still elegant and readable.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
One of those things is passing a function as an argument to another function (feature known as higher order functions or closures). &amp;nbsp;Writing listeners every time you need to use some kind of callback function can be really tedious. If you can pass callback function as an argument to another function/method it can really save time and lines of code. Javascript and Actionscript, languages that I used for some client side development, and that I considered inferior to java in many ways , have this for a long time.&lt;/div&gt;
&lt;div&gt;
Kotlin, as almost every other modern language has this feature.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Another thing that can save code and time is having default values of method arguments, so passing those arguments can be omitted in method call. This reduces, if not removes, the need for method overloading since it is more flexible way of having different combinations of arguments.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
I liked this feature in ActionScript , but Kotlin goes one step further: it supports default argument values, but it also supports passing arguments by name. This means, for example, &amp;nbsp;that you can pass only first and fourth argument, skipping second and third if they have default values. In action script if you want to pass forth argument you also need to pass all arguments before it.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
There are lots of other features that make Kotlin code shorter and more elegant then Java code.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Elegance and ease of use is not &amp;nbsp;Kotlin&#39;s only advantage over Java, &amp;nbsp; there are also features that make Kotlin more powerful, although with greater power comes more responsibility so in general it requires programmer to be more careful.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
To mention just few of them: null-safety, immutability, extension functions, lambdas, inline functions, operator overloading, range expressions... etc.&lt;/div&gt;
&lt;div&gt;
To see full list of Kotlin features check out&amp;nbsp;&lt;a href=&quot;http://confluence.jetbrains.com/display/Kotlin/Docs+Home&quot; target=&quot;_blank&quot;&gt;docs page&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&amp;nbsp;don&#39;t miss&amp;nbsp;&lt;a href=&quot;http://confluence.jetbrains.com/display/Kotlin/Comparison+to+Java&quot; target=&quot;_blank&quot;&gt;comparison to Java&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Many modern languages have very similar feature list like Kotlin: Java 8, Scala, Ceylon, Clojure (clojure is little bit different animal since it&#39;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Lisp_(programming_language)&quot; target=&quot;_blank&quot;&gt;Lisp&lt;/a&gt;&amp;nbsp;dialect). So why to choose Kotlin?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
For Java programmer Kotlin should be the easiest to switch to (except of course Java 8), since one of main goals of Kotlin is to be Java-compatible. This means that Kotlin should provide much better interoperability with Java then Scala, Clojure, Ceylon...&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
Also, Kotlin compiles as fast as java , that is another goal of Kotlin authors.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Scala is Kotlin&#39;s main competitor so it is good to know what are &lt;a href=&quot;http://confluence.jetbrains.com/display/Kotlin/Comparison+to+Scala&quot; target=&quot;_blank&quot;&gt;similarities and differences between them&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Since Android apps run on Java and Kotlin is highly interoperable with Java it is possible to write android apps using Kotlin.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Here are some useful links on how to start with it:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://blog.jetbrains.com/kotlin/running-hello-kotlin-on-android/&quot;&gt;http://blog.jetbrains.com/kotlin/running-hello-kotlin-on-android/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://hadihariri.com/2013/05/21/android-applications-with-kotlin/&quot;&gt;http://hadihariri.com/2013/05/21/android-applications-with-kotlin/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
For now, using IntelliJ IDEA is the easiest way to develop with Kotlin.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I look forward to make myself more familiar with Kotlin using it on my new android app and I will share my experience here soon.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/7341463062396741671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/7341463062396741671' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/7341463062396741671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/7341463062396741671'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2013/06/developing-android-apps-in-kotlin.html' title='Developing android apps with Kotlin'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-9056506403531152031</id><published>2013-01-25T14:51:00.000+01:00</published><updated>2013-09-19T14:09:40.047+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="memory usage"/><title type='text'>How much memory do images in android apps really use?</title><content type='html'>Recently I had some OutOfMemory issues in one my apps.&lt;br /&gt;
After analyzing logcat I could see that one image used as background is taking more then 2MB even though the image in png format was less then 200KB.&lt;br /&gt;
&lt;br /&gt;
At the first look it was confusing, but it is actually only logical when you make yourself think about it little bit more.&lt;br /&gt;
Image size in compressed format such as (jpg,png) is one thing , and Bitmap decoded from it and used for actually drawing on screen is something&amp;nbsp;completely&amp;nbsp;different.&lt;br /&gt;
&lt;br /&gt;
After quick research I found exact formula to calculate memory required for bitmap.&lt;br /&gt;
&lt;br /&gt;
Memory required by bitmap image depends on image dimensions and bitmap type.&lt;br /&gt;
&lt;br /&gt;
M = &amp;nbsp;WIDTH * HEIGHT * 4 &amp;nbsp; &amp;nbsp;(for&amp;nbsp;&lt;span style=&quot;background-color: #f7f7f7; color: #222222; font-family: Roboto, sans-serif; font-size: 14px; line-height: 19px;&quot;&gt;ARGB_8888 Bitmap - &amp;nbsp;if you need transparency&lt;/span&gt;)&lt;br /&gt;
M = &amp;nbsp;WIDTH * HEIGHT * 2 &amp;nbsp; &amp;nbsp;(for&amp;nbsp;&lt;span style=&quot;background-color: white; font-family: Arial, &#39;Liberation Sans&#39;, &#39;DejaVu Sans&#39;, sans-serif; font-size: 14px; line-height: 18px;&quot;&gt;RGB_565 Bitmap - no transparency&lt;/span&gt;)&lt;br /&gt;
&lt;br /&gt;
where result M is in bytes and WIDTH and HEIGHT are in pixels.&lt;br /&gt;
&lt;br /&gt;
So using few large images as backgrounds in your layouts can quickly lead to OutOfMemory exception on devices with low memory per app limit.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/9056506403531152031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/9056506403531152031' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/9056506403531152031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/9056506403531152031'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2013/01/how-much-memory-do-images-in-apps.html' title='How much memory do images in android apps really use?'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1890682579549650946.post-8730756067323288045</id><published>2012-10-02T14:45:00.002+02:00</published><updated>2013-09-19T14:10:24.309+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="android"/><category scheme="http://www.blogger.com/atom/ns#" term="android apps"/><category scheme="http://www.blogger.com/atom/ns#" term="cracking"/><category scheme="http://www.blogger.com/atom/ns#" term="piracy"/><title type='text'>Can android app be protected from piracy?</title><content type='html'>If you are android developer , you know how much skill, effort, creativity and&amp;nbsp;innovation&amp;nbsp;is required to make competitive android application.&lt;br /&gt;
&lt;br /&gt;
After investing your knowledge, creativity and time, you probably don&#39;t want your app to be copied, repackaged, and sold by unauthorized parties. &lt;br /&gt;
&lt;br /&gt;
So, what can we do to protect our work?&lt;br /&gt;
&lt;br /&gt;
There are many methods,like those&amp;nbsp;&lt;a href=&quot;https://docs.google.com/viewer?url=http://www.google.com/events/io/2011/static/presofiles/dgalpin_android_pirates_and_vampires.pdf&amp;amp;pli=1&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;suggested in&amp;nbsp;this presentation&lt;/b&gt;&lt;/a&gt;,&amp;nbsp;that could be used for this purpose.&lt;br /&gt;
Unfortunately, there are tools available that allow people to crack many of this protection methods, even people with very little or no knowledge at all of android development and java programming in general.&lt;br /&gt;
&lt;br /&gt;
In my apps , I use simple technique that can be described in one sentence.&lt;br /&gt;
Check if app was tampered with, and if so, make it stop working properly.&lt;br /&gt;
&lt;br /&gt;
I prefer this method since it doesn&#39;t require connection to google market server or any other server on the &amp;nbsp;net.&lt;br /&gt;
&lt;br /&gt;
Checking the signature is trivial, but it will not be of much use if the attacker can easy find the part of your code that does the checking and remove it.&lt;br /&gt;
So the hardest part of protecting application this way is to hide the code that does the checking best we can.&lt;br /&gt;
&lt;br /&gt;
Using obfuscator is basic stuff, so we use it as a first line of&amp;nbsp;defence. It will make decompiled code very hard to read and to follow program flow. The problem is that attacker doesn&#39;t actually need to understand how your app works in general, he just needs to find your protection and disable it.&lt;br /&gt;
Since all methods for checking app&amp;nbsp;authenticity (signature checking that we use is one of these methods)&amp;nbsp;are well known, attacker will probably focus on finding them in your code. Obfuscated code will rename your variables and methods to some meaningless names, throw in bunch of junk stuff etc., but calls to android framework&amp;nbsp;methods will remain unchanged and easy to find in decompiled code.&lt;br /&gt;
&lt;br /&gt;
Here is an example of the code for getting app signature:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;color: #cfe2f3; font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;Signature[] myAppSignatures = ctx.getPackageManager().getPackageInfo(ctx.getPackageName(), PackageManager.GET_SIGNATURES).signatures;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
More advanced obfuscators such as &lt;a href=&quot;http://www.saikoa.com/dexguard&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;Dexguard&lt;/b&gt;&lt;/a&gt;&amp;nbsp;can help hiding this code by using reflection to call getPackageInfo method instead of directly calling this. You also want to encrypt method name strings like &quot;getPackageInfo&quot; so that attacker can not simply search decompiled code for it.&lt;br /&gt;
Dexguard even comes with configuration template that already contains settings for doing this, you only need to uncomment few lines to use it.&lt;br /&gt;
&lt;br /&gt;
After using reflection in combination with string encryption it is very hard for attacker to find this method call in decompiled code.&lt;br /&gt;
&lt;br /&gt;
However, this level of protection is still not good enough. Why?&lt;br /&gt;
Because &amp;nbsp;tools like anti-lvl intercept getPackageInfo() method even if you use reflection with encrypted strings.&lt;br /&gt;
&lt;br /&gt;
It &amp;nbsp;does it by replacing all method.invoke(...) calls with it&#39;s own code (hook) that checks method name after the method object is already initiated. If method name equals &quot;getPackageInfo&quot; hook returns PackageInfo with fake signatures (your original signatures instead of repackaged app signature). Otherwise, if the method is not relevant for checking app authenticity, hook will just call method.invoke method as you originally intended.&lt;br /&gt;
&lt;br /&gt;
Can we do something about this?&lt;br /&gt;
&lt;br /&gt;
We can encrypt whole class instead of only encrypting string used for method invocation via reflection. With encryption applied, &amp;nbsp;Method.invoke(...) calls become invisible for cracking tool so it can not replace it with hook.&lt;br /&gt;
So, encrypting the class containing signature checking will&amp;nbsp;stop anti-lvl tool (current version&amp;nbsp;at least) to crack the app.&lt;br /&gt;
&lt;br /&gt;
You should be aware of the fact that &amp;nbsp;encrypted classes &lt;a href=&quot;http://java.dzone.com/articles/gun-great-equalizer-openjdk&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;can be decrypted&lt;/b&gt;&lt;/a&gt;, actually intercepted after decryption, but as far as I know anti-lvl doesn&#39;t yet do that.&lt;br /&gt;
&lt;br /&gt;
This means that with some additional manual work of decrypting classes before applying anti-lvl, signature checking method still can be cracked.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://beegor.blogspot.com/feeds/8730756067323288045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/1890682579549650946/8730756067323288045' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/8730756067323288045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1890682579549650946/posts/default/8730756067323288045'/><link rel='alternate' type='text/html' href='http://beegor.blogspot.com/2012/10/android-app-anti-tampering-method.html' title='Can android app be protected from piracy?'/><author><name>Igor Buzatović</name><uri>http://www.blogger.com/profile/16688136891389148746</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>