Featured FREE Whitepapers

What's New Here?

software-development-2-logo

Software architect mistakes

I think that to get up in the morning and brew a good cup of coffee is one of the best way to start the day. You know, the heady fragrance that emanates from the machine-pot, it?s delicious. When it?s ready, pour the coffee into a cup, add some sugar, and finally you got it end of the coffee making process. Have you ever thought to design a coffee making process with some diagrams, or doing the same with other banal activities such as taking a shower? Of course not. For other cases less trivial than these, including software project development, a minimal-design work can be quite useful and somewhat needed. Often questions arise; is an architecture design worth the time and effort invested in it? Well, you may answer this question first: Are there risks in the project that could be minimized by an early design activity? The more ambitious and challenging the project is, the higher the number of risks, and the more difficult it is to complete successfully. How to identifying risks. The easiest place to start is with requirements, in whatever form they take, and to look for things that seem difficult to achieve. Gathering requirements is fundamental for deciding what to do and how. However, sometimes problems arise at this starting point that lead to the ruination of the project. Some assumptions may underestimate this key phase and shake the architect role to its foundations: 1. It?s someone else? responsibility to do requirements. Domains drive the architecture choices, not vice-versa. Requirements can create architecture problems. At the very least, you need to assist the business analysts. 2. I learn the domain as I write the code; incrementally. While prototyping pieces of software is a way for mitigating engineering risks and figuring out the hardest problems, writing code could be a waste of time for analyzing a domain. Rather, it?s very cost-effective to modelling it in advance. 3. The requirements are already fully understood by the stakeholders. Clear communication is critical between people and the role of a software architect can be a very difficult one when others don?t understand what you do and why. 4. Domains are irrelevant to architecture choice. Developers may copy an architecture from a past project. Maybe just following the company standard, but ignoring the motivations behind previous choices. They are more likely to be unaware of the qualities required in the current project. 5. I already know the requirements. At least the documentation should be in your mind, but designers should use models to amplifying their reasoning abilities and unfold not clearly visible aspects that affect their own risks. Reference: Software architect mistakes from our JCG partner Giancarlo Frison at the Making Things Simple Through The Complex blog....
apache-shiro-logo

Secure Encryption in Java

Last time I wrote about cryptography, I outlined Apache Shiro crypto API and shown how to use its two symmetric ciphers. I also wrote that “You do not need more to encrypt and decrypt sensitive data in your applications.” I learned more about cryptography and found out that you need to know more. What I wrote is true to some extend, but unless you are careful your sensitive data may not be secure against all attackers. Out of the box Shiro provides Blowfish-CBC and AES-CBC encryption methods and I recommended to use them. Both have been designed to protect against passive eavesdropping attacker and are good at it. Unfortunately, real attackers are more sophisticated and may break the system based on them. Notice the “may”. The attacker can succeed only if attacked system cooperates with him at least little bit. If you want to use these ciphers, you have to know how to write the system securely. Of course, the other option is to use stronger cipher and avoid the problem completely. Few needed theoretical terms and concepts are explained in the first chapter. Second chapter shows how to encrypt data in a more secure way. Then we describe how Blowfish-CBC and AES-CBC work and show two possible attacks on them. Finally, the end of the post contains references to other resources Theory We start with a few theoretical concepts. If you do not want to read it, go directly to the chapter with the solution. First important thing to describe is the difference between a passive and an active attacker. Then we explain what are block ciphers and what is an authenticated encryption. Last two subchapters list selected vulnerable and selected secure ciphers. Active vs Passive Attacker Eavesdropping only attacker is mostly passive. He is able to read encrypted communication, but is unable to modify it or send new ciphertexts to communicating applications. He is not able to influence the communication, he only listens to it. His passivity has only one exception: the attacker is able to give unencrypted information to one of communicating parties and obtain ciphertext with that exact information. Real-world attackers are often more active. They compose their own messages and send them to communicating application. The application then assumes that those messages are encrypted, so it tries to decrypt them. The attacker observes its reaction (returned error code, time needed to answer and so on), and learn more about the cipher. If he is lucky, he may use obtained knowledge to break the cipher or to plant false information. Block Ciphers Block ciphers are able to encrypt only short messages. For example, AES can encrypt only 16 bytes long messages and Blowfish is able to encrypt only 8 bytes long messages. Longer messages are split into blocks. Each block is combined with previously encrypted blocks and passed to the block cipher. Block combining is called an operation mode and there are multiple secure ways how to do it. Two active attacks discussed in this post are attacks on CBC operation mode. Block ciphers themselves are secure. Authenticated Encryption Authenticated encryption rejects any modified ciphertext as invalid. It is not possible to take encrypted data, modify them and end up with valid ciphertext. This property is also called a ciphertext integrity. The cipher checks integrity first and rejects all modified messages the same way. As the attacker can not pass through the integrity check, he gains nothing from sending new messages to the application. Authentication and ciphertext integrity are usually, but not always, provided by the operation mode. Vulnerable Ciphers Any cipher that does not provide ciphertext integrity or authenticated encryption is probably vulnerable to some active attack. It does not matter which encryption library is used. Encryption algorithms are defined in standards and amount to the same thing regardless of the used library. Otherwise said, if it is possible to create valid ciphertext without knowing the secret key, then it is likely that some active attack exists, even if it is not know yet. This post describes two attacks CBC operation mode. Once you understand both these attacks and differences between passive and active attacker, you should be able to come up with similar attacks on CFB, CTR, OFB or other non-authenticated cipher modes. Secure Ciphers Authenticated encryptions are secure against active attackers. Most common operation modes that provide also authentication are:GCM EAX CCMReplace CBC with one of these modes (e.g. AES-EAX) and you have a cipher secure against an active attacker. Of course, secure against an active attacker does not mean that the cipher has no other real-world limitation. For example, most ciphers are safe only if the user changes the key after too much data have been encrypted. If you are serious about data encryption, you should study and know those limitations. Authenticated Encryption with Shiro This chapter shows how to use an authenticated encryption in Java. For those who skipped the theory, authenticated encryption protects against data tampering. Nobody without the secret key will be able to modify an encrypted message and an active attack on such cipher is impossible. Apache Shiro does not implement its own encryption algorithms. It delegates all work to Java Cryptography Extension (JCE) which is available in each Java runtime. Shiro ‘only’ provides easy to use API and secure defaults. Therefore, we have to do two things:install authenticated operation modes into Java Cryptography Extension, integrate Shiro with new authenticated operation modes.Install Authenticated Operation Modes Java Cryptography Extension is an extensible API. All classes and algorithms are created by providers and new provider can be installed into the system at any time. The provider can be either:installed into java runtime and be available to all java applications, distributed and initialized together with the application.We will show how to add Bouncy Castle into the project. Bouncy Castle is a provider distributed under the MIT license and contains both EAX and GCM operation modes. Bouncy Castle distributes multiple jar files, each optimized for different java version. As our demo project uses Java 6, we have to use bcprov-jdk16 library. Add maven dependency into pom.xml: <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency>Once the library is present, you have to install its provider into java security system. Run following method at the application start-up: private BouncyCastleProvider installBouncyCastle() { BouncyCastleProvider provider = new BouncyCastleProvider(); Security.addProvider(provider); return provider; }Bouncy Castle is now installed and both authenticated operation modes are available. Integrate with Shiro Shiro cryptography package is basically an easy to use facade over JCE. It configures JCE objects to use secure defaults and adds thread safety to it. Extend DefaultBlockCipherService class to take advantage of these features. Most of configuration is done by that class, but we still have to specify three things:block cipher name and parameters, operation mode, padding.Block cipher name is specified in constructor parameter. We will use AES, because it requires no additional configuration. Neither GCM nor CCM require padding, so we have to specify the padding NONE. New cipher service: class GCMCipherService extends DefaultBlockCipherService {private static final String ALGORITHM_NAME = "AES";public GCMCipherService() { super(ALGORITHM_NAME); setMode(OperationMode.GCM); setPaddingScheme(PaddingScheme.NONE); }}That is it. You may use the new authenticating cipher as any other Shiro cipher service. Test Case We created a simple test case to demonstrate that the integrity check works. It encrypts a message and changes third byte of its ciphertext. If the cipher provides an authentication, then an attempt to decrypt modified ciphertext results in runtime exception: @Test public void testGCMAuthentication() { String message = "secret message";GCMCipherService gcmCipher = new GCMCipherService(); assertIngetrityCheck(message, gcmCipher); }private void assertIngetrityCheck(String message, DefaultBlockCipherService cipher) { byte[] key = cipher.generateNewKey().getEncoded(); byte[] messageBytes = CodecSupport.toBytes(message); ByteSource encrypt = cipher.encrypt(messageBytes, key);// change the ciphertext encrypt.getBytes()[3] = 0;try { // it should be impossible to decrypt changed ciphertext cipher.decrypt(encrypt.getBytes(), key).getBytes(); } catch (Exception ex) { return; } fail("It should not be possible to decrypt changed ciphertext."); }Note on Java 7 According to documentation, Java 7 supports two authenticated operation modes: CCM and GCM. Theoretically, you should not need a third party cryptography provider. Unfortunately, Oracle could not provide a full implementation of these modes in first JDK 7 release. They would like to add it in an update release, so the situation may change in the future. Oracle bug database contains two related bugs. Java 1.7.0_01 still does not have them. Cipher Block Chaining (CBC) The last thing we needed before we can describe promised attacks is cipher block chaining (CBC) operation mode. This operation mode is sufficiently secure against passive attacker, reasonably fast and easy to implement. Unfortunately, it also is vulnerable to active attacks. Basics CBC is used to encrypt a long message with block cipher. Block ciphers are able to encrypt only short blocks of data, so it starts by splitting the message into short blocks. First and last blocks are special cases. We will explain what to do with them in following subchapters. For now, assume that the message beginning is already encrypted and its i-th block mi corresponds to ciphertext ci. Encrypt the next message block in two steps:xor the block with ciphertext of the previous block (e.g. mi?ci-1), encrypt the result with a block cipher (e.g. Blowfish(key, mi?ci-1)).Example: suppose that the secret message has three blocks and we are trying to encrypt it with Blowfish-CBC. The first block is already encrypted and its ciphertext is 1, 2, 3, 4, 5, 6, 7, 8. The second block is a byte array 1, 0, 1, 0, 1, 0, 1, 0. Step 1: xor the first block ciphertext with the second block: 1, 2, 3, 4, 5, 6, 7, 8 ? 1, 0, 1, 0, 1, 0, 1, 0 = 0, 2, 2, 4, 4, 6, 6, 8Step 2: encrypt the result with blowfish algorithm: Blowfish(secret_key, {0, 2, 2, 4, 4, 6, 6, 8})First Block – Initialization Vector First block has no previous block to be combined with. Therefore, we will generate a block of random data called initialization vector. The initialization vector is used as a very first block of data. It is xor-ed with the first message block and the result is encrypted with a block cipher. Initialization vector is send unencrypted as a first block of the ciphertext. The recipient would be unable to decrypt the ciphertext without it and there is no reason to keep it secret. Example: suppose that the secret message has three blocks and we are trying to encrypt it with Blowfish-CBC. The first block is a byte array 1, 1, 1, 1, 1, 1, 1, 1. Step 1: generate random initialization vector: 1, 8, 2, 7, 3, 6, 4, 5Step 2: xor the first block with the initialization vector: 1, 8, 2, 7, 3, 6, 4, 5 ? 1, 1, 1, 1, 1, 1, 1, 1 = 0, 9, 3, 6, 2, 7, 5, 4Step 3: encrypt the result with blowfish algorithm: Blowfish(secret_key, {0, 9, 3, 6, 2, 7, 5, 4})Step 4: combine initialization vector and ciphertext. If the result of Blowfish function in previous step is 1, 2, 3, 4, 5, 6, 7, 8, then the ciphertext is: 1, 8, 2, 7, 3, 6, 4, 5, 1, 2, 3, 4, 5, 6, 7, 8Last Block – Padding Block ciphers are able to encrypt messages of fixed length and last block is often shorter than that. As the cipher is unable to encrypt it, we need a way to add additional bytes to the end of the message. Shiro uses PKCS#5 padding by default. Each its byte is equal to the length of the padding:If the last block is too short, count how many bytes are missing and fill missing bytes with that number. If the last block has the right size, treat the message as if it would be missing whole block. Add a new padding block to it. Each its byte will be equal to the block size.Example 1: suppose that the secret message has three blocks and we are trying to encrypt it with Blowfish-CBC. The last block is byte array 1, 1, 1, 1. Padded block: 1, 1, 1, 1, 4, 4, 4, 4Example 2: suppose that the secret message has three blocks and we are trying to encrypt it with Blowfish-CBC. The last block is byte array 8, 7, 6, 5, 4, 3, 2, 1. Last block and padding: 8, 7, 6, 5, 4, 3, 2, 1, 8, 8, 8, 8, 8, 8, 8, 8Attacks Finally, we are ready to show two different attacks on CBC based ciphers and prove that the problem is real. Our sample project contains tests cases for both attacks on both AES-CBC and Blowfish-CBC ciphers. First subchapter shows how to change the beginning of encrypted text to any message of our choice. Second subchapter explains how to decrypt the ciphertext. Data Tampering Data tampering attack is possible only if the attacker already knows the content of encrypted message. Such attacker can change first message block to whatever he wishes to. In particular, it is possible to:change first 16 bytes of AES-CBC encrypted message, change first 8 bytes of Blowfish-CBC encrypted message.Potential Danger Whether this type of attack is dangerous depends a lot on circumstances. If you use the cipher to send password through network, then data tampering is not so dangerous. At worst, a legitimate user will get login denied. Similarly, if your encrypted data are stored on some read-only storage, then you do not have to worry about data tampering. However, if you are sending bank order through the network, data tampering is a real threat. If someone changes the message Pay Mark 100$ into Pay Tom 9999$, Tom will get 9999$ he should not get. The Attack Encrypted message has three parts:random initial vector, first block of ciphertext, the rest of the message.The recipient decrypts the first block of ciphertext with the block cipher. This gives him message block?initial vector. To get the message, he has to xor this value with the initial vector: message block ? initial vector ? initial vector = message block The initial vector is transferred together with the message and an active attacker can change it. If the attacker replaces the original initial vector with another iv, then the recipient will decrypt another message: message block ? initial vector ? another iv = another message Rearrange the previous equation and you get: another iv = message block ? initial vector ? another message If the attacker knows both initial vector and content of the encrypted message, then he can modify the message to anything he wants. All he has to do is to xor the original initial vector with both known message content and desired message. Whoever decrypts the modified ciphertext will obtain a modified message instead of the original one. Test Case We created a simple test case that demonstrate this attack on a message encrypted with AES-CBC. Imagine that an attacker captured an encrypted email and somehow knows what is in it: //original message private static final String EMAIL = "Hi,\n" + "send Martin all requested money please.\n\n" + "With Regards, \n" + "Accounting\n";The attacker can change only first 16 bytes of the message, so he decides to redirect the money to Andrea: //changed message private static final String MODIFICATION = "Hi,\n" + "give Andrea all requested money please.\n\n" + "With Regards, \n" + "Accounting\n";Following test case encrypts the message and modifies the ciphertext. Modified ciphertext is decrypted and compared to the expected message: @Test public void testModifiedMessage_AES() { //create cipher and the secret key StringCipherService cipher = new StringCipherService(new AesCipherService()); byte[] key = cipher.generateNewKey();//encrypt the message byte[] ciphertext = cipher.encrypt(EMAIL, key);//attack: modify the encrypted message for (int i = 0; i < 16; i++) { ciphertext[i] = (byte)(ciphertext[i] ^ MODIFICATION.getBytes()[i] ^ EMAIL.getBytes()[i]); }//decrypt and verify String result = cipher.decrypt(ciphertext, key); assertEquals(MODIFICATION, result); } Of course, similar attack can be done on Blowfish-CBC. We can change only first 8 bytes this time: @Test public void testModifiedMessage_Blowfish() { String email = "Pay 100 dollars to them, but nothing more. Accounting\n"; StringCipherService cipher = new StringCipherService(new BlowfishCipherService()); byte[] key = cipher.generateNewKey(); byte[] ciphertext = cipher.encrypt(email, key);String modified = "Pay 900 dollars to them, but nothing more. Accounting\n"; for (int i = 0; i < 8; i++) { ciphertext[i] = (byte)(ciphertext[i] ^ modified.getBytes()[i] ^ email.getBytes()[i]); } String result = cipher.decrypt(ciphertext, key); assertEquals(modified, result); } Decrypt the Cipher The second attack allows an attacker to decrypt the secret message. The attack is possible only if the application that decrypts secret messages cooperates with the attacker. Padding Oracle The attacker creates a lot of fake ciphertexts and sends them to the recipient. As he tries to decrypt those messages, one of these things will happen:the ciphertext decrypts to meaningless garbage, modified message will not be valid ciphertext at all.If the application behaves the same way in both cases, then everything is ok. If it behaves differently, then the attacker is able to decrypt the ciphertext. There is only one way how the CBC based ciphertext can be incorrect – if the padding is wrong. For example, if ciphertext contains an encrypted password, the vulnerable server may respond with “login denied” in case of wrong decrypted password and with runtime exception in case of invalid ciphertext. If this is the case, then the attacker can recover the password. General Idea Each fake message has two parts: a fake initial vector and one message block. Both are sent to the server. If it answers “padding right”, then we know that: message ? original iv ? fake iv = valid paddingThe only unknown variable in the above equation is the message. The original iv is previous ciphertext block, fake iv was created by us and the valid padding is one of 1 or 2, 2 or 3, 3, 3 or ... or 8, 8, ..., 8 and so on. Therefore, we can calculate the block content as: message = valid padding ? original iv ? fake ivAlgorithm Start by recovering the last block byte. Each fake initial vectors starts with a lot of 0 and ends with a different last byte. This way, we can be almost sure that the server answers “padding right” only on a message that ends with 1. Use the previous chapter equation to calculate the last block byte. Getting the second last byte of the message is very similar. The only difference is that we have to craft a ciphertext that decrypts into the second shortest padding 2, 2. The last byte of the message is already known, so enforcing 2 as the last value is easy. The beginning of the initial vector is unimportant and set that to 0. Then we try all possible values for the second last byte of the initial vector. Once the server answers “padding right”, we can get the second last message byte from the same formula as before: original iv ? fake iv ? 2. We calculate third last message byte out of fake message with padding 3, 3, 3; fourth out of message with padding 4, 4, 4, 4; and so on until the whole block is decrypted. Test Case The vulnerable server is simulated with a PaddingOraculum class. Each instance of this class generates a random secret key and keeps it private. It exposes only two public methods:byte[] encrypt(String message) – encrypts a string with secret key, boolean verifyPadding(byte[] ciphertext) – returns whether the padding is right.The padding oraculum attack is implemented in decryptLastBlock method. The method decrypts last block of encrypted message: private String decryptLastBlock(PaddingOraculum oraculum, byte[] ciphertext) { // extract relevant part of the ciphertext byte[] ivAndBlock = getLastTwoBlocks(ciphertext, oraculum.getBlockSize()); // modified initial vector byte[] ivMod = new byte[oraculum.getBlockSize()]; Arrays.fill(ivMod, (byte) 0);// Start with last byte of the last block and // continue to the first byte. for (int i = oraculum.getBlockSize()-1; i >= 0; i--) { // add padding to the initial vector int expectedPadding = oraculum.getBlockSize() - i; xorPad(ivMod, expectedPadding);// loop through possible values of ivModification[i] for (ivMod[i] = -128; ivMod[i] < 127; ivMod[i]++) { // create fake message and verify its padding byte[] modifiedCiphertext = replaceBeginning(ivAndBlock, ivMod); if (oraculum.verifyPadding(modifiedCiphertext)) { // we can stop looping // the ivModification[i] = // = solution ^ expectedPadding ^ ivAndBlock[i] break; } }// remove the padding from the initial vector xorPad(ivMod, expectedPadding); }// modified initial vector now contains the solution xor // original initial vector String result = ""; for (int i = 0; i < ivMod.length; i++) { ivMod[i] = (byte) (ivMod[i] ^ ivAndBlock[i]); result += (char) ivMod[i]; } return result; }Our sample project contains two test cases. One encrypts message with AES-CBC and then uses the padding oraculum to the last block of the ciphertext. The other do the same thing with Blowfish-CBC. Decrypt Blowfish-CBC test case: @Test public void testPaddingOracle_Blowfish() { String message = "secret message!";PaddingOraculum oraculum = new PaddingOraculum( new BlowfishCipherService()); //Oraculum encrypts the message with a secret key. byte[] ciphertext = oraculum.encrypt(message); //use oraculum to decrypt the message String result = decryptLastBlock(oraculum, ciphertext); //the original message had padding 1 assertEquals("essage!"+(char)1, result); }Resources Additional related resources:Free online Stanford crypto class. The original paper with padding oracle attack from 2002. A good alternative explanation of padding oracle attack. A beast attack on CBC explained. It is based on padding oracle attack. Stack exchange thread on common cryptography mistakes.End No cipher provides absolute safety against all possible attacks. Instead, they provide protection only against well defined classes of attacks. Ciphers are secure only as long as the potential threat to the system matches the cipher strength. Protection against an active attack can be done in two ways:Make an active attack impossible by design. Use an authenticated encryption.Using an authenticated encryption is arguably easier and should be the preferred option. Ruling out the active attacker is error prone and more risky. All code sample used in this post are available on Github. Reference: Secure Encryption in Java from our JCG partner Maria Jurcovicova at the This is Stuff blog....
java-logo

Threading stories: ThreadLocal in web applications

This week I spend reasonable time to eliminate all our ThreadLocal variables in our web applications. The reason was that they created classloader leaks and we coudn’t undeploy our applications properly anymore. Classloader leaks happen when a GC root keeps referencing an application object after the application was undeployed. If an application object is still referenced after undeploy, then the whole class loader can’t be garbage collected cause the considered object references your applications class file which in turn references the classloader. This will cause an OutOfMemoryError after you’ve undeployed and redeployed a couple of times. ThreadLocal is one classic candidate that can easily create classloader leaks in web applications. The server is managing its threads in a pool. These threads live longer then your web application. In fact they don’t die at all until the underlying JVM dies. Now, if you put a ThreadLocal in a pooled thread that references an object of your class you *must* be careful. You need to make sure that this variable is removed again using ThreadLocal.remove(). The issue in web applications is: where is the right place to safely remove ThreadLocal variables? Also, you may not want to modify that “removing code” every time a colleague decided to add another ThreadLocal to the managed threads. We’ve developed a wrapper class around thread local that keeps all the thread local variables in one single ThreadLocal variable. Here is the code. public class ThreadLocalUtil {private final static ThreadLocal<ThreadVariables> THREAD_VARIABLES = new ThreadLocal<ThreadVariables>() {/** * @see java.lang.ThreadLocal#initialValue() */ @Override protected ThreadVariables initialValue() { return new ThreadVariables(); } };public static Object getThreadVariable(String name) { return THREAD_VARIABLES.get().get(name); }public static Object getThreadVariable(String name, InitialValue initialValue) { Object o = THREAD_VARIABLES.get().get(name); if (o == null) { THREAD_VARIABLES.get().put(name, initialValue.create()); return getThreadVariable(name); } else { return o; } }public static void setThreadVariable(String name, Object value) { THREAD_VARIABLES.get().put(name, value); }public static void destroy() { THREAD_VARIABLES.remove(); } }public class ThreadVariables extends HashMap<String, Object> { }public abstract class InitialValue {public abstract Object create();}The advantage of the utility class is that no developer needs to manage the thread local variable lifecycle individually. The class puts all the thread locals in one map of variables. The destroy() method can be invoked where you can safely remove all thread locals in your web application. In our case thats a ServletRequestListener -> requestDestroyed() method. You will also need to place finally blocks elsewhere. Typical places are near the HttpServlet, in the init(), doPost(), doGet() methods. This may remove all thread locals in the pooled worker threads after the request is done or an exception is thrown unexpectedly. Sometimes it happens that the main thread of the server leaks thread local variables. If that is the case you need to find the right places where to call the ThreadLocalUtil -> destroy() method. To do that figure out where the main thread actually *creates* the thread variables. You could use your debugger to do that. Many guys out there suggest to ommit ThreadLocal in web applications for several reasons. It can be very difficult to remove them in a pooled thread environment so that you can undeploy the applications safely. ThreadLocal variables can be useful, but it’s fair to consider other techniques before applying them. An alternative for web applications to carry request scope parameters is the HttpServletRequest. Many web frameworks allow for generic request parameter access as well as request/session attribute access, without ties to the native Servlet/Portlet API. Also many framework support request scoped beans to be injected into an object tree using dependency injection. All these options fulfill most requirements and should be considered prior to using ThreadLocal. Reference: Threading stories: ThreadLocal in web applications from our JCG partner Niklas....
javafx-logo

JavaFX 2 GameTutorial Part 2

Introduction This is the second installment of a series of blog entries relating to a JavaFX 2 Game Tutorial. If you have not read Part 1 please see the introduction section of the JavaFX 2 Game Tutorial. To recap in Part 1, I mention some aspects of game play and a simple demo of a prototype spaceship (comprised of simple shapes) that is capable of navigating via the mouse. Disclaimer: This is a long tutorial so if you just want to run the demo just Click HERE. The demo is called Atom Smasher where you generate atoms (spheres) that collide. You may freeze the game to add more atoms. The objective is to have more than one atom alive and bouncing around. A text displays the current number of atoms floating around. Before beginning our discussion on a game loop I wanted to give you some background history about games and animation.History Back in the day (during the 80s-90s) many game programmers attempted to animate images has encountered the infamous screen flicker problem. This is where your sprites (graphic images) will often flash and make the game look quite awful. All monitors have a refresh rate where certain intervals the pixels will be redrawn (called vertical retrace CRTs). For example, if the refresh rate is 80 Hz it is approximately 80 times a second the screen is redrawn. If you are modifying things on the screen you can often be out ofsyncbecause of being in the middle of a refresh interval. What should you do about this? Well, actually there are two things that will help remedy this problem (double buffering & knowing when the cycle is occurring). Some clever developers created a technique called double buffering. Double buffering is a technique which consists of two surfaces where each takes turns on becoming the displayable surface and the other is an offscreen area (buffer surface). This technique is really a digital sleight of hand trick where the developer can pre calculate the sprites and their positions to be drawn on the offscreen surface. Once you are finished drawing on the offscreen buffer the code will switch it as the displayable surface. An important thing to point out is that we still have an issue due to the fact that we need to be notified when the refresh interval is about to begin the redraw process. In Java this ability is built in via the BufferStrategy API. So, where am I going with this? Sometimes explaining the past strategies will help us appreciate what we have today. Do we need to do this in JavaFX? Nope. Have no fear JavaFX is here! All of the issues thatI’vementioned are all taken care of for us by using JavaFX’s Scene graph API. However, most games will still use the old fashion way of animating graphics and updating the game world called the ‘Game Loop’. The Game Loop Simply put the game loop is responsible for updating sprites (graphics), checking collision, and cleanup. Older game loops will check for key and mouse events as part of the loop. Since JavaFX abstracts events to allow the Scene or individual nodes to handle events the ability to listen to low level events aren’t necessary in our game loop. Shown below is a source code snippet of a typical game loop which will update sprites, check collisions, and cleanup sprites at each cycle. You will notice the Duration object from JavaFX 2.x which represents 60 divided by 1000 milliseconds or 60 frames per second(FPS). Each frame will call the handle() method of the JavaFX’s EventHandler interface in order to update the game world. Hypothetically, I’ve create three methods updateSprites(), checkCollisions(), and cleanupSprites() that will be invoked to handle sprites in the game. final Duration oneFrameAmt = Duration.millis(1000/60); final KeyFrame oneFrame = new KeyFrame(oneFrameAmt, new EventHandler() {@Override public void handle(javafx.event.ActionEvent event) {// update actors updateSprites();// check for collision checkCollisions();// removed dead things cleanupSprites();} }); // oneFrame// sets the game world's game loop (Timeline) TimelineBuilder.create() .cycleCount(Animation.INDEFINITE) .keyFrames(oneFrame) .build() .play();The above code snippet is really all you need to create a simple game or animation. However, you may want to take things to the next level. You may want to create a game engine that can manage sprites and the state of the game world. Game Engine A game engine is a fancy name for a utility or library responsible for encapsulating the game world, running the game loop, managing sprites, physics, etc. This is essentially a small game framework that allows you to extend or reuse so you don’t have to reinvent the wheel when creating a 2D game from scratch. To fast forward I created a UML class diagram of a design of a game engine. Shown below is Figure 1 A JavaFX Game Engine Class diagram.Figure 1. A JavaFX 2 Game Engine DesignIn Figure 1 A JavaFX 2 Game Engine Design you will notice three classes a GameWorld, SpriteManager, and Sprite. The GameWorld class is responsible for initializing the game state, executing the game loop, updating sprites, handling sprite collisions, and cleaning up. Next is the SpriteManager class which in charge of managing sprites by adding, removing, and other house keeping for collisions. Lastly, is the Sprite class which is responsible for maintaining the state of an image (Actor). In a 2D world a sprite can contain the object’s velocity, rotation, scene node or image that eventually gets rendered at each cycle (key frame/frames per second). Just a quick reminder on UML notation:Plus symbol ‘+‘ denotes that a class member is public. Minus symbol ‘-‘ denotes that a class member isprivate Hash symbol ‘#‘ denotes that a class member is protected.GameWorld Below is the source code implementation of the GameWorld class. Click to expand. Later you will see a class diagram depicting a simple demo game that will extend the GameWorld class (see AtomSmasher). package carlfx.gameengine;import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.animation.TimelineBuilder; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.util.Duration;/** * This application demonstrates a JavaFX 2.x Game Loop. * Shown below are the methods which comprise of the fundamentals to a * simple game loop in JavaFX: * * <strong>initialize()</strong> - Initialize the game world. * <strong>beginGameLoop()</strong> - Creates a JavaFX Timeline object containing the game life cycle. * <strong>updateSprites()</strong> - Updates the sprite objects each period (per frame) * <strong>checkCollisions()</strong> - Method will determine objects that collide with each other. * <strong>cleanupSprites()</strong> - Any sprite objects needing to be removed from play. * * @author cdea */ public abstract class GameWorld {/** The JavaFX Scene as the game surface */ private Scene gameSurface; /** All nodes to be displayed in the game window. */ private Group sceneNodes; /** The game loop using JavaFX's <code>Timeline</code> API.*/ private static Timeline gameLoop;/** Number of frames per second. */ private final int framesPerSecond;/** Title in the application window.*/ private final String windowTitle;/** * The sprite manager. */ private final SpriteManager spriteManager = new SpriteManager();/** * Constructor that is called by the derived class. This will * set the frames per second, title, and setup the game loop. * @param fps - Frames per second. * @param title - Title of the application window. */ public GameWorld(final int fps, final String title) { framesPerSecond = fps; windowTitle = title; // create and set timeline for the game loop buildAndSetGameLoop(); }/** * Builds and sets the game loop ready to be started. */ protected final void buildAndSetGameLoop() {final Duration oneFrameAmt = Duration.millis(1000/getFramesPerSecond()); final KeyFrame oneFrame = new KeyFrame(oneFrameAmt, new EventHandler() {@Override public void handle(javafx.event.ActionEvent event) {// update actors updateSprites();// check for collision checkCollisions();// removed dead things cleanupSprites();} }); // oneFrame// sets the game world's game loop (Timeline) setGameLoop(TimelineBuilder.create() .cycleCount(Animation.INDEFINITE) .keyFrames(oneFrame) .build()); }/** * Initialize the game world by update the JavaFX Stage. * @param primaryStage */ public abstract void initialize(final Stage primaryStage);/**Kicks off (plays) the Timeline objects containing one key frame * that simply runs indefinitely with each frame invoking a method * to update sprite objects, check for collisions, and cleanup sprite * objects. * */ public void beginGameLoop() { getGameLoop().play(); }/** * Updates each game sprite in the game world. This method will * loop through each sprite and passing it to the handleUpdate() * method. The derived class should override handleUpdate() method. * */ protected void updateSprites() { for (Sprite sprite:spriteManager.getAllSprites()){ handleUpdate(sprite); } }/** Updates the sprite object's information to position on the game surface. * @param sprite - The sprite to update. */ protected void handleUpdate(Sprite sprite) { }/** * Checks each game sprite in the game world to determine a collision * occurred. The method will loop through each sprite and * passing it to the handleCollision() * method. The derived class should override handleCollision() method. * */ protected void checkCollisions() { // check other sprite's collisions spriteManager.resetCollisionsToCheck(); // check each sprite against other sprite objects. for (Sprite spriteA:spriteManager.getCollisionsToCheck()){ for (Sprite spriteB:spriteManager.getAllSprites()){ if (handleCollision(spriteA, spriteB)) { // The break helps optimize the collisions // The break statement means one object only hits another // object as opposed to one hitting many objects. // To be more accurate comment out the break statement. break; } } } }/** * When two objects collide this method can handle the passed in sprite * objects. By default it returns false, meaning the objects do not * collide. * @param spriteA - called from checkCollision() method to be compared. * @param spriteB - called from checkCollision() method to be compared. * @return boolean True if the objects collided, otherwise false. */ protected boolean handleCollision(Sprite spriteA, Sprite spriteB) { return false; }/** * Sprites to be cleaned up. */ protected void cleanupSprites() { spriteManager.cleanupSprites(); }/** * Returns the frames per second. * @return int The frames per second. */ protected int getFramesPerSecond() { return framesPerSecond; }/** * Returns the game's window title. * @return String The game's window title. */ public String getWindowTitle() { return windowTitle; }/** * The game loop (Timeline) which is used to update, check collisions, and * cleanup sprite objects at every interval (fps). * @return Timeline An animation running indefinitely representing the game * loop. */ protected static Timeline getGameLoop() { return gameLoop; }/** * The sets the current game loop for this game world. * @param gameLoop Timeline object of an animation running indefinitely * representing the game loop. */ protected static void setGameLoop(Timeline gameLoop) { GameWorld.gameLoop = gameLoop; }/** * Returns the sprite manager containing the sprite objects to * manipulate in the game. * @return SpriteManager The sprite manager. */ protected SpriteManager getSpriteManager() { return spriteManager; }/** * Returns the JavaFX Scene. This is called the game surface to * allow the developer to add JavaFX Node objects onto the Scene. * @return */ public Scene getGameSurface() { return gameSurface; }/** * Sets the JavaFX Scene. This is called the game surface to * allow the developer to add JavaFX Node objects onto the Scene. * @param gameSurface The main game surface (JavaFX Scene). */ protected void setGameSurface(Scene gameSurface) { this.gameSurface = gameSurface; }/** * All JavaFX nodes which are rendered onto the game surface(Scene) is * a JavaFX Group object. * @return Group The root containing many child nodes to be displayed into * the Scene area. */ public Group getSceneNodes() { return sceneNodes; }/** * Sets the JavaFX Group that will hold all JavaFX nodes which are rendered * onto the game surface(Scene) is a JavaFX Group object. * @param sceneNodes The root container having many children nodes * to be displayed into the Scene area. */ protected void setSceneNodes(Group sceneNodes) { this.sceneNodes = sceneNodes; }}SpriteManager A sprite manager class is a helper class to assist the game loop to keep track of sprites. Normally a sprite manager will contain all sprites and each sprite contains a JavaFX Node that is displayed onto the Scene graph. Shown below is the source code. Click to expand. package carlfx.gameengine;import java.util.*;/** * Sprite manager is responsible for holding all sprite objects, and cleaning up * sprite objects to be removed. All collections are used by the JavaFX * application thread. During each cycle (animation frame) sprite management * occurs. This assists the user of the API to not have to create lists to * later be garbage collected. Should provide some performance gain. * @author cdea */ public class SpriteManager { /** All the sprite objects currently in play */ private final static List GAME_ACTORS = new ArrayList<>();/** A global single threaded list used to check collision against other * sprite objects. */ private final static List CHECK_COLLISION_LIST = new ArrayList<>();/** A global single threaded set used to cleanup or remove sprite objects * in play. */ private final static Set CLEAN_UP_SPRITES = new HashSet<>();/** */ public List getAllSprites() { return GAME_ACTORS; }/** * VarArgs of sprite objects to be added to the game. * @param sprites */ public void addSprites(Sprite... sprites) { GAME_ACTORS.addAll(Arrays.asList(sprites)); }/** * VarArgs of sprite objects to be removed from the game. * @param sprites */ public void removeSprites(Sprite... sprites) { GAME_ACTORS.removeAll(Arrays.asList(sprites)); }/** Returns a set of sprite objects to be removed from the GAME_ACTORS. * @return CLEAN_UP_SPRITES */ public Set getSpritesToBeRemoved() { return CLEAN_UP_SPRITES; }/** * Adds sprite objects to be removed * @param sprites varargs of sprite objects. */ public void addSpritesToBeRemoved(Sprite... sprites) { if (sprites.length > 1) { CLEAN_UP_SPRITES.addAll(Arrays.asList((Sprite[]) sprites)); } else { CLEAN_UP_SPRITES.add(sprites[0]); } }/** * Returns a list of sprite objects to assist in collision checks. * This is a temporary and is a copy of all current sprite objects * (copy of GAME_ACTORS). * @return CHECK_COLLISION_LIST */ public List getCollisionsToCheck() { return CHECK_COLLISION_LIST; }/** * Clears the list of sprite objects in the collision check collection * (CHECK_COLLISION_LIST). */ public void resetCollisionsToCheck() { CHECK_COLLISION_LIST.clear(); CHECK_COLLISION_LIST.addAll(GAME_ACTORS); }/** * Removes sprite objects and nodes from all * temporary collections such as: * CLEAN_UP_SPRITES. * The sprite to be removed will also be removed from the * list of all sprite objects called (GAME_ACTORS). */ public void cleanupSprites() {// remove from actors list GAME_ACTORS.removeAll(CLEAN_UP_SPRITES);// reset the clean up sprites CLEAN_UP_SPRITES.clear(); } }Sprite The Sprite class represents an image or node to be displayed onto the JavaFX Scene graph. In a 2D game a sprite will contain additional information such as its velocity for the object as it moves across the scene area. The game loop will call the update() and collide() method at every interval of a key frame. Shown below is the source code. Click to expand. package carlfx.gameengine;import java.util.ArrayList; import java.util.List; import javafx.animation.Animation; import javafx.scene.Node;/** * The Sprite class represents a image or node to be displayed. * In a 2D game a sprite will contain a velocity for the image to * move across the scene area. The game loop will call the update() * and collide() method at every interval of a key frame. A list of * animations can be used during different situations in the game * such as rocket thrusters, walking, jumping, etc. * @author cdea */ public abstract class Sprite {/** Animation for the node */ public List animations = new ArrayList<>();/** Current display node */ public Node node;/** velocity vector x direction */ public double vX = 0;/** velocity vector y direction */ public double vY = 0;/** dead? */ public boolean isDead = false;/** * Updates this sprite object's velocity, or animations. */ public abstract void update();/** * Did this sprite collide into the other sprite? * * @param other - The other sprite. * @return */ public boolean collide(Sprite other) { return false; } }JavaFX 2 Game Loop Demo – Atom Smasher Whew! If you’ve got this far you are one brave soul. Let’s take a small break and try out the demo I created using the game engine above. Shown below is a Java Webstart button to launch the game demo. Later, you will see the design and source code detailing how it was created. Requirements:Java 7 or later JavaFX 2.0.2 2.1 or later Windows XP or later (Should be available soon for Linux/MacOS)DemoGameLoopPart2 Design Below is a class diagram of the game demo called Atom Smasher which uses the game engine framework mentioned earlier. Shown below is Figure 2 Atom Smasher Class Diagram.Figure 2. Atom Smasher Class DiagramGameLoopPart2 The GameLoopPart2 is the driver or main JavaFX application that runs the game. This creates a GameWorld object to be initialized and starts the game loop. Shown below is the source code. Click to expand. package carlfx;import carlfx.gameengine.GameWorld; import javafx.application.Application; import javafx.stage.Stage;/** * The main driver of the game. * @author cdea */ public class GameLoopPart2 extends Application {GameWorld gameWorld = new AtomSmasher(60, "JavaFX 2 GameTutorial Part 2 - Game Loop"); /** * @param args the command line arguments */ public static void main(String[] args) { launch(args); }@Override public void start(Stage primaryStage) { // setup title, scene, stats, controls, and actors. gameWorld.initialize(primaryStage);// kick off the game loop gameWorld.beginGameLoop();// display window primaryStage.show(); }}AtomSmasher AtomSmasher is a derived class of the GameWorld class. It creates many spheres that animate with random velocities, colors and positions. Button controls lets the user generate more ‘atoms’ (JavaFX Circle nodes). As each atom collides with one another they will invoke the implode() method that produces a fade transition animation. You will notice how easy it is to implement this game by simply implementing initialize(), handleUpdate(), handleCollision(), and cleanupSprites() methods. Once implemented the game engine does the rest. The initialize() method creates the button controls for the user. To update the sprites positions or change the game state you will implement the handleUpdate() method. To compare all sprites if they have collided with one another you will implement the handleCollision(). The last part of the game loop’s life cycle is cleaning up sprites. Cleaning up means updating the sprite manger and updating the JavaFX Scene (removing nodes). Shown below is the source code. Click to expand. package carlfx;import carlfx.gameengine.GameWorld; import carlfx.gameengine.Sprite; import java.util.Random; import javafx.animation.Timeline; import javafx.event.EventHandler; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.ButtonBuilder; import javafx.scene.control.Label; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBoxBuilder; import javafx.scene.layout.VBox; import javafx.scene.layout.VBoxBuilder; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.stage.Stage; import static javafx.animation.Animation.Status.RUNNING; import static javafx.animation.Animation.Status.STOPPED;/** * This is a simple game world simulating a bunch of spheres looking * like atomic particles colliding with each other. When the game loop begins * the user will notice random spheres (atomic particles) floating and * colliding. The user is able to press a button to generate more * atomic particles. Also, the user can freeze the game. * * @author cdea */ public class AtomSmasher extends GameWorld { /** Read only field to show the number of sprite objects are on the field*/ private final static Label NUM_SPRITES_FIELD = new Label();public AtomSmasher(int fps, String title){ super(fps, title); }/** * Initialize the game world by adding sprite objects. * @param primaryStage */ @Override public void initialize(final Stage primaryStage) { // Sets the window title primaryStage.setTitle(getWindowTitle());// Create the scene setSceneNodes(new Group()); setGameSurface(new Scene(getSceneNodes(), 640, 580)); primaryStage.setScene(getGameSurface());// Create many spheres generateManySpheres(150);// Display the number of spheres visible. // Create a button to add more spheres. // Create a button to freeze the game loop. final Timeline gameLoop = getGameLoop(); VBox stats = VBoxBuilder.create() .spacing(5) .translateX(10) .translateY(10) .children(HBoxBuilder.create() .spacing(5) .children(new Label("Number of Particles: "), // show no. particles NUM_SPRITES_FIELD).build(),// button to build more spheres ButtonBuilder.create() .text("Regenerate") .onMousePressed(new EventHandler() { @Override public void handle(MouseEvent arg0) { generateManySpheres(150); }}).build(),// button to freeze game loop ButtonBuilder.create() .text("Freeze/Resume") .onMousePressed(new EventHandler() {@Override public void handle(MouseEvent arg0) { switch (gameLoop.getStatus()) { case RUNNING: gameLoop.stop(); break; case STOPPED: gameLoop.play(); break; } }}).build() ).build(); // (VBox) stats on children// lay down the controls getSceneNodes().getChildren().add(stats); }/** * Make some more space spheres (Atomic particles) */ private void generateManySpheres(int numSpheres) { Random rnd = new Random(); Scene gameSurface = getGameSurface(); for (int i=0; i (gameSurface.getWidth() - (circle.getRadius() * 2))) { newX = gameSurface.getWidth() - (circle.getRadius() * 2); }// check for the bottom of screen the height newY is greater than height // minus radius times 2(height of sprite) double newY = rnd.nextInt((int) gameSurface.getHeight()); if (newY > (gameSurface.getHeight() - (circle.getRadius() * 2))) { newY = gameSurface.getHeight() - (circle.getRadius() * 2); }circle.setTranslateX(newX); circle.setTranslateY(newY); circle.setVisible(true); circle.setId(b.toString());// add to actors in play (sprite objects) getSpriteManager().addSprites(b);// add sprite's getSceneNodes().getChildren().add(0, b.node);} }/** * Each sprite will update it's velocity and bounce off wall borders. * @param sprite - An atomic particle (a sphere). */ @Override protected void handleUpdate(Sprite sprite) { if (sprite instanceof Atom) { Atom sphere = (Atom) sprite;// advance the spheres velocity sphere.update();// bounce off the walls when outside of boundaries if (sphere.node.getTranslateX() > (getGameSurface().getWidth() - sphere.node.getBoundsInParent().getWidth()) || sphere.node.getTranslateX() < 0 ) { sphere.vX = sphere.vX * -1; } if (sphere.node.getTranslateY() > getGameSurface().getHeight()- sphere.node.getBoundsInParent().getHeight() || sphere.node.getTranslateY() < 0) { sphere.vY = sphere.vY * -1; } } }/** * How to handle the collision of two sprite objects. Stops the particle * by zeroing out the velocity if a collision occurred. * @param spriteA * @param spriteB * @return */ @Override protected boolean handleCollision(Sprite spriteA, Sprite spriteB) { if (spriteA.collide(spriteB)) { ((Atom)spriteA).implode(this); ((Atom)spriteB).implode(this); getSpriteManager().addSpritesToBeRemoved(spriteA, spriteB); return true; } return false; }/** * Remove dead things. */ @Override protected void cleanupSprites() { // removes from the scene and backend store super.cleanupSprites();// let user know how many sprites are showing. NUM_SPRITES_FIELD.setText(String.valueOf(getSpriteManager().getAllSprites().size()));} }Atom The Atom class extends from the Sprite class. An atom is a sprite that appears like a spherical object that moves across the scene. An atom will have a random radius, color, and velocity. As each atom sprite collides with another atom they will animate a fade transition (the implode() method). Shown below is the source code. Click to expand. package carlfx;import carlfx.gameengine.GameWorld; import carlfx.gameengine.Sprite; import javafx.animation.FadeTransitionBuilder; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.paint.Color; import javafx.scene.paint.RadialGradient; import javafx.scene.paint.RadialGradientBuilder; import javafx.scene.paint.Stop; import javafx.scene.shape.Circle; import javafx.scene.shape.CircleBuilder; import javafx.util.Duration;/** * A spherical looking object (Atom) with a random radius, color, and velocity. * When two atoms collide each will fade and become removed from the scene. The * method called implode() implements a fade transition effect. * * @author cdea */ public class Atom extends Sprite {public Atom(double radius, Color fill) { Circle sphere = CircleBuilder.create() .centerX(radius) .centerY(radius) .radius(radius) .cache(true) .build();RadialGradient rgrad = RadialGradientBuilder.create() .centerX(sphere.getCenterX() - sphere.getRadius() / 3) .centerY(sphere.getCenterY() - sphere.getRadius() / 3) .radius(sphere.getRadius()) .proportional(false) .stops(new Stop(0.0, fill), new Stop(1.0, Color.BLACK)) .build();sphere.setFill(rgrad);// set javafx node to a circle node = sphere;}/** * Change the velocity of the atom particle. */ @Override public void update() { node.setTranslateX(node.getTranslateX() + vX); node.setTranslateY(node.getTranslateY() + vY); }@Override public boolean collide(Sprite other) { if (other instanceof Atom) { return collide((Atom)other); } return false; }/** * When encountering another Atom to determine if they collided. * @param other Another atom * @return boolean true if this atom and other atom has collided, * otherwise false. */ private boolean collide(Atom other) {// if an object is hidden they didn't collide. if (!node.isVisible() || !other.node.isVisible() || this == other) { return false; }// determine it's size Circle otherSphere = other.getAsCircle(); Circle thisSphere = getAsCircle(); double dx = otherSphere.getTranslateX() - thisSphere.getTranslateX(); double dy = otherSphere.getTranslateY() - thisSphere.getTranslateY(); double distance = Math.sqrt( dx * dx + dy * dy ); double minDist = otherSphere.getRadius() + thisSphere.getRadius() + 3;return (distance < minDist); }/** * Returns a node casted as a JavaFX Circle shape. * @return Circle shape representing JavaFX node for convenience. */ public Circle getAsCircle() { return (Circle) node; }/** * Animate an implosion. Once done remove from the game world * @param gameWorld - game world */ public void implode(final GameWorld gameWorld) { vX = vY = 0; FadeTransitionBuilder.create() .node(node) .duration(Duration.millis(300)) .fromValue(node.getOpacity()) .toValue(0) .onFinished(new EventHandler() { @Override public void handle(ActionEvent arg0) { isDead = true; gameWorld.getSceneNodes().getChildren().remove(node); } }) .build() .play(); } }Conclusion Hopefully you’ve got a chance to understand the fundamentals of a gaming loop and later apply the knowledge by implementing a robust game engine. Although, I briefly mention collision I am saving that for Part 4 of these tutorials. Please stay tuned for Part 3 where we will get into input using the keyboard or mouse. Feel free to experiment. Let me know what you come up with. To obtain the source code please download the link to a jar file below by using the ‘Save link As‘ option in your browser. If you are on a Windows system you can change the extension from ‘jar‘ to ‘zip‘ to be easily expanded. It will contain a directory ‘src‘ with the source code. The source code location: http://www.jroller.com/carldea/resource/javafx2.0_games/part2source_code.jar The published version of the source code is at theGitHub called(JFXGen)for you to clone and fork to your hearts content (It’s there for you to use for your own projects). Enjoy. https://github.com/carldea/JFXGen git clonegit@github.com:carldea/JFXGen.git Reference: JavaFX 2 GameTutorial Part 2 from our JCG partner Carl Dea at the Carl’s FX Blog blog....
javaone-logo

JavaOne 2012 Analysis – Submitted Proposals and Speaker Distribution

Beginning some time last year I started to have a closer look at conferences and their speakers. My main interest was to find out who was speaking how often. One conference was missing in this analysis because I really was not sure what can be published without breaking the confidentiality of the information. Being a member of the program committee for the second time this year and seeing all those wonderful sessions forced me to take another look at it and finally today I have at least some percentages to show to you. A big thank you goes out to Oracle’s Sharat Chander for giving the permission to do that! Based on the complete data for what has been submitted to JavaOne 2012 in San Francisco I will let you have a look at types, distribution and speakers. Every number given here is a percentage and the numbers behind them are still confidential. And again: This is an analysis of the complete submitted data. This doesn’t tell you anything about what is going to be selected! The voting is still ongoing and the different program committees are hard at work reviewing every single proposal. Submission Types First of all let’s look at the general distribution of submitted types independently of any track. Speakers could select any of five different types for their submission. The classic session, a BoF (Birds of a feather) a tutorial, a HoL (Hands on Lab) and for the first time this year a community keynote. Not a big surprise that most of the submissions are sessions (70,14%). Second most proposed content are BoFs. Followed by tutorials, HoLs and some community keynote proposals. Even if this sounds very concrete, there is still some motion in here. Some BoFs might become sessions and the other way around.Submission TypesSubmissions per Track Next most interesting figure is the general distribution of submissions per track. Seven tracks are there to chose from. Starting with the Core Java Platform and finishing with Java on Card and Devices. It is good to see a very evenly distributed number of proposals for every track. Lead by the Development Tools and Techniques track (24,15%) both Java ME, Java Card Embedded and Devices (8,21%) and Emerging Languages (5,86%) are the bottom end. Very few proposals are moved around from track to track during the voting process but it happens. I don’t expect the final distribution to differ heavily from the one shown below.Distribution per TrackInternal vs. External Submissions The no 1 question discussed a lot in the past is the number of sessions given by Oracle employees. even if I would love to make an educated guess here, anything I can show you is the distribution with regards to the proposals. I have looked at the first speaker of every session and assigned it an internal or external flag (yes, that took some time ;)). More than 2/3rd (71%) of the submissions come from external (aka non-Oracle)speakers. Even if I have seen some combined proposals also this is a clear sign, that JavaOne is a community driven conference.External vs. Internal SpeakersBut where exactly is Oracle jumping in? Are there differences in submissions per track if we look at the internal speakers? Internal proposals have a stronger focus on Embedded Java, the Core Platform and JavaFX compared with the external submissions.Submission Distribution by internal speakersSubmission Distribution by external speakersWhat do we learn from all that? JavaOne is going to be a great, community driven conference with a lot of awesome sessions to come! If you haven’t done so take a look and register for it! The final program is going to be announced in a few weeks and there still is plenty of time to find a flight and a hotel near by. Reference: JavaOne 2012 Analysis – Submitted Proposals and Speaker Distribution from our JCG partner Markus Eisele at the Enterprise Software Development with Java blog....
play-framework-logo

Writing modules for Play 2, part 2: Interceptors

In the first part of this tutorial, we looked at the bare basics for creating, publishing and calling a module. The module we created didn’t really do much, so now it’s time to look at expaning the functionality using some of Play’s features. 1. Interceptors Interceptors allow you to intercept calls to controllers, and augment or block their behaviour. In the first sample application, we added an explicit call to MyLogger to log a message to the console. If we scale that up, and you want to use this oh-so-useful plugin for every controller method call, you’re going to be writing a lot of boilerplate code. Interceptors allow us to automatically apply actions, and so reduce boilerplate. 1.1 Add the code In the app directory, create a new package called actions. In here, we’re going to add the LogMe annotation, and LogMeAction that will be executed whenever the annotation is present. LogMe.java is, at this point, a very simple annotation that doesn’t take any parameters package actions;import play.mvc.With;import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/** * @author Steve Chaloner (steve@objectify.be) */ @With(LogMeAction.class) @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) @Inherited @Documented public @interface LogMe { }Take a look at the annotations, and you’ll With(LogInAction.class) – this lets Play know that when this annotation is encountered, it should execute an LogInAction before the actual target. package actions;import play.mvc.Action; import play.mvc.Http; import play.mvc.Result;/** * @author Steve Chaloner (steve@objectify.be) */ public class LogMeAction extends Action { @Override public Result call(Http.Context context) throws Throwable { System.out.println("MyLogger: " + context.request().path()); return delegate.call(context); } }This is pretty elegant stuff – the action has a generic parameter type of LogMe, which gives access to any parameters given to the LogMe annotation. This allows you to customise behaviour of the action. We’ll see this in action when we add some extra features. Once your code – in this case, another class to System.out, is done then you return the result of delegate.class(context) to resume the normal execution flow. In the meantime, if @LogMe is added to a controller method, the path of the action will be logged to the console; if @LogMe is added to a controller, the invocation of any method in that controller will result in the path being logged to the console. 1.2 Update Build.scala Since we have a new version of mylogger, we should change the version number. Open project/Build.scala and change val appVersion = "1.0-SNAPSHOT"to val appVersion = "1.1"1.3 Make sure your project changes are detected If you’re already running the Play console in mylogger/project-code, you need to execute “reload” for the changes to Build.scala to be picked up. If don’t have the console open, open it now – the changes will be picked up automatically on start-up. [mylogger] $ reload [info] Loading project definition from C:\Temp\mylogger\project-code\project [info] Set current project to mylogger (in build file:/C:/Temp/mylogger/project-code/)1.4 Clean and publish As noted earlier, it’s always a good idea to clean before publishing to ensure you’re not pushing out any objects that shouldn’t be there. [mylogger] $ clean [success] Total time: 0 s, completed Mar 19, 2012 9:17:25 PM [mylogger] $ publish-local [info] Packaging /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1- 1.1-sources.jar ... [info] Done packaging. [info] Wrote /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1-1.1 .pom [info] Updating {file:/tmp/mylogger/project-code/}mylogger... [info] Done updating. [info] :: delivering :: mylogger#mylogger_2.9.1;1.1 :: 1.1 :: release :: Mon Mar 19 21:17:30 CET 2012 [info] Generating API documentation for main sources... [info] Compiling 3 Java sources to /tmp/mylogger/project-code/target/scala-2.9.1 /classes... [info] delivering ivy file to /tmp/mylogger/project-code/target/scala-2.9.1 /ivy-1.1.xml model contains 7 documentable templates [info] API documentation generation successful. [info] Packaging /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1-1.1 -javadoc.jar ... [info] Done packaging. [info] Packaging /tmp/mylogger/project-code/target/scala-2.9.1/mylogger_2.9.1-1.1.jar ... [info] Done packaging. [info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework /../repository/local/mylogger/mylogger_2.9.1/1.1/poms/mylogger_2.9.1.pom [info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework /../repository/local/mylogger/mylogger_2.9.1/1.1/jars/mylogger_2.9.1.jar [info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework /../repository/local/mylogger/mylogger_2.9.1/1.1/srcs/mylogger_2.9.1-sources.jar [info] published mylogger_2.9.1 to /home/steve/development/play/play-2.0/framework /../repository/local/mylogger/mylogger_2.9.1/1.1/docs/mylogger_2.9.1-javadoc.jar [info] published ivy to /home/steve/development/play/play-2.0/framework/../repository /local/mylogger/mylogger_2.9.1/1.1/ivys/ivy.xml [success] Total time: 3 s, completed Mar 19, 2012 9:17:31 PMNote the version of the module has changed in the logging. If you still see 1.0-SNAPSHOT, make sure you reloaded the project before publishing! 1.5 Update the sample application Back in the sample application, change the module version you require in project/Build.scala val appDependencies = Seq( "mylogger" % "mylogger_2.9.1" % "1.1" )Reload, and run “dependencies” to ensure you have the correct version. You can now update app/controllers/Application.java to use this new code: package controllers;import actions.LogMe; import play.mvc.Controller; import play.mvc.Result; import views.html.index;@LogMe public class Application extends Controller { public static Result index() { return ok(index.render("Your new application is ready.")); } }Run this example, and you’ll now see MyLogger output applied through the annotation. 2. Added interceptor parameters Just having the path of the request logged is not particulary useful or exciting. What if a specific log message should be given for each controller or controller method? In this case, we need to add some parameters. 2.1 Change the annotation signature Upload actions/LogMe.java to take a value() parameter – this is the default annotation parameter, and so doesn’t need to be explicitly named when used. The value defaults to an empty string, so a standard message can be provided in the action if one isn’t present here. public @interface LogMe { String value() default ""; }In the action, the inherited configuration field is typed to the generic parameter (in this case, LogMe) and gives access to the parameters. Update the call(Http.Context) method to take advantage of this. public Result call(Http.Context context) throws Throwable { String value = configuration.value(); if (value == null || value.isEmpty()) { value = context.request().path(); } System.out.println("MyLogger: " + value); return delegate.call(context); }2.2 Publish the changes Repeat steps 1.2 to 1.4 again, this time changing appVersion to 1.2 2.3 Update the sample application Just like before, update the dependency version in Build.scala, reload and confirm with “dependencies”. Now you can add a message to the LogMe annotation: @LogMe("This is my log message") public class Application extends ControllerRun the application, and now you’ll see your annotation message in the console. [info] play - Application started (Dev) MyLogger: This is my log message3. Make the interceptors interact Now you (hopefully) have the hang of this, we’re going to speed up a bit. In this section, we’re going to look at how interceptors can interact with each other. Play applies interceptors first to the method, and then to controller, so if the same annotation is present at both the method and controller level it will be executed twice. The LogMe annotation can be applied to both the class level and the method level, but what if you have a general logging message for the entire controller except for one method that requires a different message? Also, we only want one logging message invocation per invocation. To achieve this, we can use the context that’s passed into each action. 3.1 Update the module Update LogMeAction to give it awareness of previous invocations: package actions;import play.mvc.Action; import play.mvc.Http; import play.mvc.Result;/** * @author Steve Chaloner (steve@objectify.be) */ public class LogMeAction extends Action { public static final String ALREADY_LOGGED = "already-logged";@Override public Result call(Http.Context context) throws Throwable { Result result;if (context.args.containsKey(ALREADY_LOGGED)) { // skip the logging, just continue the execution result = delegate.call(context); } else { // we're not using the value here, only the key, but this // mechanism can also be used to pass objects context.args.put(ALREADY_LOGGED, "");String value = configuration.value(); if (value == null || value.isEmpty()) { value = context.request().path(); } System.out.println("MyLogger: " + value);result = delegate.call(context); }return result; } }Update the version number, clean, reload, and publish-local. 3.2 Update the sample application We’re going to add a second annotation, this time to the index method. This will override the controller-level annotation. So, update the dependency number in Build.scala, reload and run. package controllers;import actions.LogMe; import play.mvc.Controller; import play.mvc.Result; import views.html.index;@LogMe("This is my log message") public class Application extends Controller { @LogMe("This is my method-specific log message") public static Result index() { return ok(index.render("Your new application is ready.")); } }When you access http://localhost:9000, you will now see this in the console: @LogMe("This is my log message") [info] play - Application started (Dev) MyLogger: This is my method-specific log message4. It’s beer time again You now have an infrastructure that supports parameterised actions. Remember that lots of things can be passed as annotation parameters, but – crucially – not everything. You may need to get creative for some of your tasks! You can download the complete source code here. Reference: Writing modules for Play 2, part 2: Interceptors from our JCG partner Steve Chaloner at the Objectify blog....
javafx-logo

JavaFX 2 GameTutorial Part 1

Introduction I believe most software developers at one point in their lives as a youngster (young person) may become compelled to create games to help them learn a programming languages (I know I did). Back in the day my first computer was actually a Franklin Ace 1000 and later an Apple ][. While developing games on those systems it was pretty challenging. For starters you had to learn assembly language (6502) and there were virtually little to no tools to create sprites (graphics assets). One of my favorite games that I believe was probably the first real time strategy (RTS) game was Rescue Raiders (1984). Let's fast forward to 2012 where computers, graphics tool kits, libraries, and game engines have come a long way since then. Many APIs will provide much of the plumbing that will shield the user of the API so that they may focus on making their games fun and exciting. Speaking of APIs JavaFX 2.x is not only a great UI toolkit to create nice looking applications, but you can make fun games. With JavaFX 2.x you will be able to create games that can kill time with hours of fun!figure 1 SVG of a spaceshipGrowing up I was always fascinated with science fiction movies such as Star wars and Star trek. I've always wanted to create a simple top view display game (2D) where I could control my spaceship similar to the classic game Asteroids. However as time went by a friend shared with me the game Star Craft 1 and Brood wars I was just astonished. I really like the game play still to this very day, so I wanted to adopt some of the elements of the game such as navigating units and troops using the mouse pointer and buttons (ie: The Terran Battle Cruiser). In this blog entry (Part 1) I will be briefly explain the game play or navigation of a simple spaceship using simple shapes. There isn't code to show in part 1 (this blog entry), but a simple application to demonstrate how the ship will behave in the final game. As we progress through the series you will notice incremental changes such as cool sprites, sounds, etc. Remember the final game will just be a spaceship avoiding enemy ships and firing back with sound effects. The ship will appear like the one depicted at the beginning of this blog entry (figure 1). I would like to create a series of blog entries (six parts) detailing tutorials to create a JavaFX 2.x game. Below is a brief summary of the series: Part 1 - Introduction (Click here to run demo) Part 2 - Game loop Part 3 - Input / (Mouse, Keyboard) Part 4 - Sprites / Collision Part 5 - Sound Part 6 - Concluding thoughts Requirements & DesignCreate a prototype of a spaceship using basic shapes. Rotate the spaceship clockwise or counter clockwise depending on the screen location of a right mouse click. Fire a projectile when primary button is pressed. Display mouse press (x, y) screen coordinates Display angles to rotate the ships nose (front of the ship) Display the direction (clockwise or counter clockwise) of the rotation of the spaceshipShown in figure 2 is a simple prototype using simple shapes to help us focus on the math. A good principle is to create a functional prototype before investing a lot of time in drawing your graphics assets.figure 2 Spaceship Prototype(MX, MY) – Mouse press (x, y) coordinate space on the JavaFX Scene. (vx, vy) – End angle or mouse press(x, y) coordinate converted to Cartesian coordinates relative to the center of the ship. (ux, uy) – Start angle or previous mouse press(x, y) coordinate converted to Cartesian coordinates relative to the center of the ship. U’s angle: The angle of the start of the ships nose rotation. In a Cartesian coordinate system (1,0) the nose is pointing west or zero degrees. As the ship rotates counter clockwise the angle increases. When moving in a clockwise direction the rotation angle will be negative numbers. V’s angle: The angle of the ships nose rotation where it should stop. In a Cartesian coordinate system (1,0) the nose is pointing east or zero degrees. As the ship rotates counter clockwise the angle increases. When moving in a clockwise direction the rotation angle will be negative numbers. Direction: The rotation of the ship nose to turn the ship clockwise or counter clockwise. When clicking the mouse to turn the ship when less than 180 degrees the ship will turn towards the mouse click instead of turning the other way which is greater than 180 degrees (the long way).Demo Requirements:Java 7 or later JavaFX 2.0 or later Windows XP or later (Should be available soon for Linux/MacOS)A simple prototype of the navigation and weapon systems for the spaceship. Instructions:Right click (on Windows) mouse to fly ship. Primary (left click on Windows mouse) to fire weapon.Click here to run demo References Franklin Ace – Vintage Computer : http://www.vintage-computer.com/franklin.shtml Apple ][ – Vintage Computer: http://en.wikipedia.org/wiki/Apple_II Rescue Raiders - Wikipedia: http://en.wikipedia.org/wiki/Rescue_Raiders Star wars – Movie Database: http://www.imdb.com/title/tt0076759/ Star trek – Movie Database: http://www.imdb.com/title/tt0796366/ Star craft – Wikipedia: http://en.wikipedia.org/wiki/Star_Craft Star craft Brood wars – Wikipedia: http://en.wikipedia.org/wiki/StarCraft:_Brood_War http://en.wikipedia.org/wiki/Rescue_Raiders Reference: JavaFX 2 GameTutorial Part 1 from our JCG partner Carl Dea at the Carl’s FX blog....
akka-logo

Word Count MapReduce with Akka

In my ongoing workings with Akka, i recently wrote an Word count map reduce example. This example implements the Map Reduce model, which is very good fit for a scale out design approach. FlowThe client system (FileReadActor) reads a text file and sends each line of text as a message to the ClientActor. The ClientActor has the reference to the RemoteActor ( WCMapReduceActor ) and the message is passed on to the remote actor The server (WCMapReduceActor) gets the message. The Actor uses the PriorityMailBox to decide the priority of the message and filters the queue accordingly. In this case, the PriorityMailBox is used to segregate the message between the mapreduce requests and getting the list of results (DISPLAY_LIST)message from the aggregate actor. The WCMapReduceActor sends across the messages to the MapActor (uses RoundRobinRouter dispatcher) for mapping the words After mapping the words, the message is send across to the ReduceActor(uses RoundRobinRouter dispatcher) for reducing the words The reduced result(s) are send to the Aggregate Actor that does an in-memory aggregation of the resultThe following picture details how the program has been structuredThe code base for the program is available at the following location – https://github.com/write2munish/Akka-Essentials. For more information on MapReduce, read the post MapReduce for dummies. Reference: Word Count MapReduce with Akka from our JCG partner Munish K Gupta at the Akka Essentials blog....
software-development-2-logo

Frameworks vs Libraries as Inheritance vs Composition?

For quite some time inheritance was the dominant model of structuring programs in OO languages like Java. Very often it was used as a mechanism for reusing code – “common” functions where placed in an abstract class, so that subclasses can use them. However, this often proves to be very limiting, as you can only inherit from a single class. The code becomes constrained and tied to one particular framework-specific class. Not to mention testing – such base classes often depend on outside state, making tests hard to setup. That’s why nowadays time and again you can hear that you should prefer composition over inheritance (see for example this StackOverflow question). When using composition, you can leverage multiple re-usable chunks of code, and combine them in an arbitrary way. Also using IoC/Dependency Injection strongly favors composition. I think the above inheritance-composition opposition strongly resembles the framework-library distinction. When using a framework, you are forced into a specific structure, where you must model your code in one specific way. Quite obviously it’s often hard or impossible to use two frameworks in one layer/module. That’s how hacks, ugly workarounds, reflection madness, etc. is born. Libraries on the other hand (unless they are deliberately wrongly written), can be freely combined. Just like composition of classes, you can compose usage of many libraries in one module. Your code can be kept clean and only use the library functionality it really requires. I’m not saying that frameworks are bad – just like inheritance, they may be very useful if used in the correct places. However, next time you put your code into a framework, maybe it’s better to think twice: can this functionality be implemented using composition, with the help of a library? Won’t this make my code cleaner and more maintainable? Reference: Frameworks vs Libraries as Inheritance vs Composition? from our W4G partner Adam Warski at the Blog of Adam Warski blog....
java-logo

Runtime vs Compile-Time Classpath

This should really be a simple distinction, but I’ve been answering a slew of similar questions on Stackoverflow, and often people misunderstand the matter. So, what is a classpath? A set of all the classes (and jars with classes) that are required by your application. But there are two, or actually three distinct classpaths:compile-time classpath. Contains the classes that you’ve added in your IDE (assuming you use an IDE) in order to compile your code. In other words, this is the classpath passed to “javac” (though you may be using another compiler). runtime classpath. Contains the classes that are used when your application is running. That’s the classpath passed to the “java” executable. In the case of web apps this is your /lib folder, plus any other jars provided by the application server/servlet container test classpath – this is also a sort of runtime classpath, but it is used when you run tests. Tests do not run inside your application server/servlet container, so their classpath is a bit differentMaven defines dependency scopes that are really useful for explaining the differences between the different types of classpaths. Read the short description of each scope. Many people assume that if they successfully compiled the application with a given jar file present, it means that the application will run fine. But it doesn’t – you need the same jars that you used to compile your application to be present on your runtime classpath as well. Well, not necessarily all of them, and not necessarily only them. A few examples:you compile the code with a given library on the compile-time classpath, but forget to add it to the runtime classpath. The JVM throws NoClasDefFoundError, which means that a class is missing, which was present when the code was compiled. This error is a clear sign that you are missing a jar file on your runtime classpath that you have on your compile-time classpath. It is also possible that a jar you depend on in turn depends on a jar that you don’t have anywhere. That’s why libraries (must) have their dependencies declared, so that you know which jars to put on your runtime classpath containers (servlet containers, application servers) have some libraries built-in. Normally you can’t override the built-in dependencies, and even when you can, it requires additional configuration. So, for example, you use Tomcat, which provides the servlet-api.jar. You compile your application with the servlet-api.jar on your compile-time classpath, so that you can use HttpServletRequest in your classes, but do not include it in your WEB-INF/lib folder, because tomcat will put its own jar in the runtime classpath. If you duplicate the dependency, you may get bizarre results, as classloaders get confused. a framework you are using (let’s say spring-mvc) relies on another library to do JSON serialization (usually Jackson). You don’t actually need Jackson on your compile-time classpath, because you are not referring to any of its classes or even spring classes that refer to them. But spring needs Jackson internally, so the jackson jar must be in WEB-INF/lib (runtime classpath) for JSON serialization to work.The cases might be complicated even further, when you consider compile-time constants and version mismatches, but the general point is this: the classpaths that you use for compiling and for running the application are different, and you should be aware of that. Reference: Runtime Classpath vs Compile-Time Classpath from our JCG partner Bozhidar Bozhanov at the Bozho’s tech blog blog....
Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close