Featured FREE Whitepapers

What's New Here?

software-development-2-logo

Logical vs physical clock optimistic locking

Introduction In my previous post I demonstrated why optimistic locking is the only viable solution for application-level transactions. Optimistic locking requires a version column that can be represented as:a physical clock (a timestamp value taken from the system clock) a logical clock (an incrementing numeric value)This article will demonstrate why logical clocks are better suited for optimistic locking mechanisms. System time The system time is provided by the operating system internal clocking algorithm. The programmable interval timer periodically sends an interrupt signal (with a frequency of 1.193182 MHz). The CPU receives the time interruption and increments a tick counter. Both Unix and Window record time as the number of ticks since a predefined absolute time reference (an epoch). The operating system clock resolution varies from 1ms (Android) to 100ns (Windows) and to 1ns (Unix). Monotonic time To order events, the version must advance monotonically. While incrementing a local counter is a monotonic function, system time might not always return monotonic timestamps. Java has two ways of fetching the current system time. You can either use:System#currentTimeMillis(), that gives you the number of milliseconds elapsed since Unix epochThis method doesn’t give you monotonic time results because it returns the wall clock time which is prone to both forward and backward adjustments (if NTP is used for system time synchronization).For monotonic currentTimeMillis, you can check Peter Lawrey’s solution or Bitronix Transaction Manager Monotonic Clock. System#nanoTime(), that returns the number of nanoseconds elapsed since an arbitrarily chosen time referenceThis method tries to use the current operating system monotonic clock implementation, but it falls back to wall clock time if no monotonic clock could be found. Argument 1: System time is not always monotonically incremented. Database timestamp precision The SQL-92 standard defines the TIMESTAMP data type as YYYY-MM-DD hh:mm:ss. The fraction part is optional and each database implements a specific timestamp data type:RDBMS Timestamp resolutionOracle TIMESTAMP(9) may use up to 9 fractional digits (nano second precision).MSSQL DATETIME2 has a precision of 100ns.MySQL MySQL 5.6.4 added microseconds precision support for TIME, DATETIME, and TIMESTAMP types (e.g. TIMESTAMP(6)). Previous MySQL versions discard the fractional part of all temporal types.PostgreSQL Both TIME and TIMESTAMP types have microsecond precision.DB2 TIMESTAMP(12) may use up to 12 fractional digits (picosecond precision).When it comes to persisting timestamps, most database servers offer at least 6 fractional digits. MySQL users have long been waiting for a more precise temporal type and the 5.6.4 version had finally added microsecond precision. On a pre-5.6.4 MySQL database server, updates might be lost during the lifespan of any given second. That’s because all transactions updating the same database row will see the same version timestamp (which points to the beginning of the current running second). Argument 2: Pre-5.6.4 MySQL versions only support second precision timestamps. Handling time is not that easy Incrementing a local version number is always safer because this operation doesn’t depends on any external factors. If the database row already contains a higher version number your data has become stale. It’s as simple as that. On the other hand, time is one of the most complicated dimension to deal with. If you don’t believe me, check the for daylight saving time handling considerations. It took 8 versions for Java to finally come up with a mature Date/Time API. Handling time across application layers (from JavaScript, to Java middle-ware to database date/time types) makes matters worse. Argument 3: Handling system time is a challenging job. You have to hanlde leap seconds, daylight saving, time zones and various time standards. Lessons from distributed computing Optimistic locking is all about event ordering, so naturally we’re only interested in the happened-before relationship. In distributed computing, logical clocks are favored over physical ones (system clock), because networks time synchronization implies variable latencies. Sequence number versioning is similar to Lamport timestamps algorithm, each event incrementing only one counter. While Lamport timestamps was defined for multiple distributed nodes event synchronization, database optimistic locking is much simpler, because there is only on node (the database server) where all transactions are synchronized (coming from concurrent client connections). Argument 4: Distributed computing favors logical clock over physical ones, because we are only interested in event ordering anyway. Conclusion Using physical time might seem convenient at first, but it turns out to be a naive solution. In a distributed environment, perfect system time synchronization is mostly unlikely. All in all, you should always prefer logical clocks when implementing an optimistic locking mechanism.Reference: Logical vs physical clock optimistic locking from our JCG partner Vlad Mihalcea at the Vlad Mihalcea’s Blog blog....
agile-logo

Six Tips for Interviewing Scrum Masters, Part 2

Now that you know what you expect from your Scrum Master’s job (the deliverables), and you know the essential and desirable skills (the first three tips), you can focus on creating the interview questions and audition. (If you have not yet read Six Tips for Interviewing Scrum Masters, Part 1 for the first three tips, please do so now.) Tip 4: Create Behavior-Description Questions for Your Scrum Master Based on Essential Qualities, Preferences, and Non-Technical Skills For initiative, you might ask behavior-description questions like these:Give me an example of a recent time you thought the team was stuck. How did you know the team was stuck and what did you do? (You want to know if the SM was command-and-control, interfering or helpful.) Tell me about a time when your Product Owner was convinced the story was as small as possible, but the story was a month long. Have you encountered something like this? (Maybe a month is longer than what the candidate encountered. Maybe it wasn’t the PO. Listen to their experience.) What happened? (Listen for what the SM did or did not do. Different Scrum Masters facilitate differently. There Is No Right Answer.) Tell me about a recent time the team had many stories in progress and didn’t finish at the end of a sprint. What happened? (Listen for what the SM did or did not do. Different Scrum Masters facilitate differently. There Is No Right Answer.)For flexibility, consider these questions:What do you consider negotiable in a Scrum team? Why? Give me a recent example of that flexibility. Give me an example of a time you and the team were stymied by something. What happened? Have you ever needed to compromise as a Scrum Master? Tell me about it.Again, you have to listen for the context and what the Scrum Master did in the different context for the project and the organization. There is no right answer. There are answers that don’t fit your context. Make sure you keep reading down to see my question about learning from past experiences. For perseverance, you might like these questions:Tell me about a time you advocated for something you wanted. Tell me about a work obstacle you had to overcome. Tell me about a time you had to maintain focus when it seemed everyone else was losing their focus.Do you see the pattern? Apply behavior-description questions to your essential qualities, preferences and non-technical skills. Tip 5: Create at Least One Audition Based on Deliverables Back in Six Tips for Interviewing Scrum Masters, Part 1, I said that you needed to define deliverables. I suggested a potential list of 10 deliverables. You might have these candidate auditions:Facilitate a standup Facilitate a retrospective Look at a Scrum board and tell you what it means Look at a team’s measurements and tell you what they meanI’m not saying these are the best auditions, because I don’t know what you need Your Scrum Master to do. These are candidate auditions. I have a lot more about how to create auditions in Hiring Geeks That Fit. Tip 6: Ignore Certifications and Look for the Growth Mindset I have never been a fan of certifications. If I have to choose between a candidate with a certification and a candidate with a growth mindset, I’ll select the candidate with the growth mindset. (Remember, you can buy a certification by taking a class. That’s it.) Certifications are good for learning. They are not good for helping people prove they have executed anything successfully. When you interview for the growth mindset, you ask behavior-description questions. When they answer in a way that intrigues you, you ask, “What did you learn from that?” (a reflective hypothetical question). Then ask, “How have you put that learning into practice?” (a behavior-description question). Now, you have yourself a terrific conversation, which is the basis for a great interview. Okay, there are my six tips for hiring a Scrum Master. If you want to understand how to hire without fear, read Hiring Geeks That Fit.Reference: Six Tips for Interviewing Scrum Masters, Part 2 from our JCG partner Johanna Rothman at the Managing Product Development blog....
software-development-2-logo

Chained Access Delegation Pattern

Suppose a medium-scale enterprise that sells bottled water has a RESTful API (Water API) that can be used to update the amount of water consumed by a registered user. Any registered user can access the API via any client application. It could be an Android app, an iOS app, or even a web application. The company only provides the API—anyone can develop client applications to consume it. All the user data is stored in Microsoft Active Directory. Client applications shouldn’t be able to access the API directly and query to find out information about users. Only registered users can access the API. These users shouldn’t be able to see other users’ information. At the same time, for each update made by a user, the Water API must update the user’s healthcare record maintained at MyHealth.org. The user also has a personal record at MyHealth.org, and it too exposes an API (MyHealth API). The Water API has to call the MyHealth API to update the user record on the user’s behalf. In summary, a mobile application accesses the Water API on behalf of the end user, and then the Water API has to access the MyHealth API on behalf of the end user. The Water API and the MyHealth API are in two independent domains. This suggests the need for an access-delegation protocol. Again, the catch here is the statement, “the Water API must also update the user’s healthcare record maintained at MyHealth.org.” The challenge has two solutions. In the first solution, the end user must get an access token from MyHealth.org for the Water API (the Water API acts as the OAuth client), and then the Water API must store the token internally according to the user’s name. Whenever the user sends an update through a mobile application to the Water API, the app first updates its own record and then finds the MyHealth access token corresponding to the end user and uses it to access the MyHealth API. With this approach, the Water API has the overhead of storing the MyHealth API access token, and it should refresh the access token whenever needed. The second solution is explained in the above figure. It’s built around the OAuth 2.0 Chain Grant Type profile. The mobile app must carry a valid access token to access the Water API on behalf of the end user. In step 3, the Water API talks to its own authorization server to validate the access token. Then, in step 4, the Water API exchanges the access token it got from the mobile application for a JWT access token. The JWT access token is a special access token that carries some meaningful data, and it’s also signed by the authorization server in the Water API’s domain. The JWT includes the end user’s local identifier as well as its mapping identifier in the MyHealth domain. The end user must permit this action at the Water API domain. In step 6, the Water API accesses the MyHealth API using the JWT access token. The MyHealth API validates the JWT access token by talking to its own authorization server. It verifies the signature; and, if it’s signed by a trusted entity, the access token is treated as valid. Because the JWT includes the mapping username from the MyHealth domain, it can identify the corresponding local user record. However, this raises a security concern. If you let users update their profiles in the Water API domain with the mapping MyHealth identifier, they can map it to any user identifier, and this leads to a security hole. To avoid that, the account-mapping step must initiate an OpenID Connect authentication with the MyHealth domain. When the user wants to add their MyHealth account identifier, the Water API domain initiates the OpenID Connect authentication flow and receives the corresponding ID token. Then the account mapping is done with the user identifier in the ID token. This is one of the ten API security patterns covered in my book Advanced API Security. You can find more details about this from the book.Reference: Chained Access Delegation Pattern from our JCG partner Prabath Siriwardena at the Facile Login blog....
jboss-drools-logo

Trace output with Drools

Drools 6 includes a trace output that can help get an idea of what is going on in your system,  and how often things are getting executed, and with how much data. It can also help to understand that Drools 6 is now a goal based algorithm, using a linking mechanism to link in rules for evaluation. More details on that here: http://www.javacodegeeks.com/2013/11/r-i-p-rete-time-to-get-phreaky.html The first thing to do is set your slf4j logger to trace mode:       <appender name="consoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!-- %l lowers performance --> <!--<pattern>%d [%t] %-5p %l%n %m%n</pattern>--> <pattern>%d [%t] %-5p %m%n</pattern> </encoder> </appender><logger name="org.drools" level="trace"/><root level="info"><!-- TODO We probably want to set default level to warn instead --> <appender-ref ref="consoleAppender" /> </root> </configuration> Let’s take the shopping example, you can find the Java and Drl files for this here:https://github.com/droolsjbpm/drools/blob/master/drools-examples/src/main/resources/org/drools/examples/shopping/Shopping.drl https://github.com/droolsjbpm/drools/blob/master/drools-examples/src/main/java/org/drools/examples/shopping/ShoppingExample.javaRunning the example will give output a very detailed and long log of execution. Initially you’ll see objects being inserted, which causes linking. Linking of nodes and rules is explained in the Drools 6 algorithm link. In summary 1..n nodes link in a segment, when object are are inserted. 2014-10-02 02:35:09,009 [main] TRACE Insert [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] 2014-10-02 02:35:09,020 [main] TRACE LinkNode notify=false nmask=1 smask=1 spos=0 rules= Then 1..n segments link in a rule. When a Rule is linked in it’s schedule on the agenda for evaluation. 2014-10-02 02:35:09,043 [main] TRACE LinkRule name=Discount removed notification 2014-10-02 02:35:09,043 [main] TRACE Queue RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,043 [main] TRACE Queue Added 1 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] When it eventually evaluates a rule it will indent as it visits each node, as it evaluate from root to tip. Each node will attempt to tell you how much data is being inserted, updated or deleted at that point. 2014-10-02 02:35:09,046 [main] TRACE Rule[name=Apply 10% discount if total purchases is over 100] segments=2 TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,047 [main] TRACE 1 [ AccumulateNode(12) ] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,047 [main] TRACE Segment 1 2014-10-02 02:35:09,047 [main] TRACE 1 [ AccumulateNode(12) ] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,047 [main] TRACE rightTuples TupleSets[insertSize=2, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,056 [main] TRACE 2 [RuleTerminalNode(13): rule=Apply 10% discount if total purchases is over 100] TupleSets[insertSize=1, deleteSize=0, updateSize=0] You can use this information to see how often rules evaluate, how much linking and unlinking happens, how much data propagates and more important how much wasted work is done.  Here is the full log: 2014-10-02 02:35:08,889 [main] DEBUG Starting Engine in PHREAK mode 2014-10-02 02:35:08,927 [main] TRACE Adding Rule Purchase notification 2014-10-02 02:35:08,929 [main] TRACE Adding Rule Discount removed notification 2014-10-02 02:35:08,931 [main] TRACE Adding Rule Discount awarded notification 2014-10-02 02:35:08,933 [main] TRACE Adding Rule Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,009 [main] TRACE Insert [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] 2014-10-02 02:35:09,020 [main] TRACE LinkNode notify=false nmask=1 smask=1 spos=0 rules= 2014-10-02 02:35:09,020 [main] TRACE LinkSegment smask=2 rmask=2 name=Discount removed notification 2014-10-02 02:35:09,025 [main] TRACE LinkSegment smask=2 rmask=2 name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,028 [main] TRACE LinkNode notify=true nmask=1 smask=1 spos=0 rules=[RuleMem Purchase notification], [RuleMem Discount removed notification], [RuleMem Discount awarded notification], [RuleMem Apply 10% discount if total purchases is over 100] 2014-10-02 02:35:09,028 [main] TRACE LinkSegment smask=1 rmask=1 name=Purchase notification 2014-10-02 02:35:09,028 [main] TRACE LinkSegment smask=1 rmask=3 name=Discount removed notification 2014-10-02 02:35:09,043 [main] TRACE LinkRule name=Discount removed notification 2014-10-02 02:35:09,043 [main] TRACE Queue RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,043 [main] TRACE Queue Added 1 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,043 [main] TRACE LinkSegment smask=1 rmask=1 name=Discount awarded notification 2014-10-02 02:35:09,043 [main] TRACE LinkSegment smask=1 rmask=3 name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,043 [main] TRACE LinkRule name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,043 [main] TRACE Queue RuleAgendaItem [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,043 [main] TRACE Queue Added 2 [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,043 [main] TRACE Added Apply 10% discount if total purchases is over 100 to eager evaluation list. 2014-10-02 02:35:09,044 [main] TRACE Insert [fact 0:2:14633842:14633842:2:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Product@df4b72] 2014-10-02 02:35:09,044 [main] TRACE Insert [fact 0:3:732189840:732189840:3:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Product@2ba45490] 2014-10-02 02:35:09,044 [main] TRACE Insert [fact 0:4:939475028:939475028:4:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Purchase@37ff4054] 2014-10-02 02:35:09,045 [main] TRACE BetaNode insert=1 stagedInsertWasEmpty=true 2014-10-02 02:35:09,045 [main] TRACE LinkNode notify=true nmask=1 smask=1 spos=1 rules=[RuleMem Purchase notification] 2014-10-02 02:35:09,045 [main] TRACE LinkSegment smask=2 rmask=3 name=Purchase notification 2014-10-02 02:35:09,045 [main] TRACE LinkRule name=Purchase notification 2014-10-02 02:35:09,046 [main] TRACE Queue RuleAgendaItem [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,046 [main] TRACE Queue Added 1 [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,046 [main] TRACE BetaNode insert=1 stagedInsertWasEmpty=true 2014-10-02 02:35:09,046 [main] TRACE LinkNode notify=true nmask=1 smask=1 spos=1 rules=[RuleMem Apply 10% discount if total purchases is over 100] 2014-10-02 02:35:09,046 [main] TRACE LinkSegment smask=2 rmask=3 name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,046 [main] TRACE LinkRule name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,046 [main] TRACE Added Apply 10% discount if total purchases is over 100 to eager evaluation list. 2014-10-02 02:35:09,046 [main] TRACE Insert [fact 0:5:8996952:8996952:5:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Purchase@894858] 2014-10-02 02:35:09,046 [main] TRACE BetaNode insert=2 stagedInsertWasEmpty=false 2014-10-02 02:35:09,046 [main] TRACE BetaNode insert=2 stagedInsertWasEmpty=false 2014-10-02 02:35:09,046 [main] TRACE Rule[name=Apply 10% discount if total purchases is over 100] segments=2 TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,047 [main] TRACE 1 [ AccumulateNode(12) ] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,047 [main] TRACE Segment 1 2014-10-02 02:35:09,047 [main] TRACE 1 [ AccumulateNode(12) ] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,047 [main] TRACE rightTuples TupleSets[insertSize=2, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,056 [main] TRACE 2 [RuleTerminalNode(13): rule=Apply 10% discount if total purchases is over 100] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,057 [main] TRACE Segment 1 2014-10-02 02:35:09,057 [main] TRACE 2 [RuleTerminalNode(13): rule=Apply 10% discount if total purchases is over 100] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,057 [main] TRACE Rule[name=Apply 10% discount if total purchases is over 100] segments=2 TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,057 [main] TRACE 3 [ AccumulateNode(12) ] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,057 [main] TRACE Rule[name=Purchase notification] segments=2 TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,057 [main] TRACE 4 [JoinNode(5) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Purchase]] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,057 [main] TRACE Segment 1 2014-10-02 02:35:09,057 [main] TRACE 4 [JoinNode(5) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Purchase]] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,058 [main] TRACE rightTuples TupleSets[insertSize=2, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,058 [main] TRACE 5 [RuleTerminalNode(6): rule=Purchase notification] TupleSets[insertSize=2, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,058 [main] TRACE Segment 1 2014-10-02 02:35:09,058 [main] TRACE 5 [RuleTerminalNode(6): rule=Purchase notification] TupleSets[insertSize=2, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,058 [main] TRACE Fire "Purchase notification" [[ Purchase notification active=false ] [ [fact 0:4:939475028:939475028:4:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Purchase@37ff4054] [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] ] ] Customer mark just purchased shoes 2014-10-02 02:35:09,060 [main] TRACE Fire "Purchase notification" [[ Purchase notification active=false ] [ [fact 0:5:8996952:8996952:5:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Purchase@894858] [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] ] ] Customer mark just purchased hat 2014-10-02 02:35:09,061 [main] TRACE Removing RuleAgendaItem [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,061 [main] TRACE Queue Removed 1 [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,061 [main] TRACE Rule[name=Discount removed notification] segments=2 TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,061 [main] TRACE 6 [NotNode(8) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,061 [main] TRACE Segment 1 2014-10-02 02:35:09,061 [main] TRACE 6 [NotNode(8) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,061 [main] TRACE rightTuples TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,061 [main] TRACE 7 [RuleTerminalNode(9): rule=Discount removed notification] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,061 [main] TRACE Segment 1 2014-10-02 02:35:09,061 [main] TRACE 7 [RuleTerminalNode(9): rule=Discount removed notification] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,061 [main] TRACE Fire "Discount removed notification" [[ Discount removed notification active=false ] [ null [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] ] ] Customer mark now has a discount of 0 2014-10-02 02:35:09,063 [main] TRACE Removing RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,063 [main] TRACE Queue Removed 1 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,063 [main] TRACE Fire "Apply 10% discount if total purchases is over 100" [[ Apply 10% discount if total purchases is over 100 active=false ] [ [fact 0:6:2063009760:1079902208:6:null:NON_TRAIT:120.0] [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] ] ] 2014-10-02 02:35:09,071 [main] TRACE Insert [fact 0:7:874153561:874153561:7:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Discount@341a8659] 2014-10-02 02:35:09,071 [main] TRACE LinkSegment smask=2 rmask=3 name=Discount removed notification 2014-10-02 02:35:09,071 [main] TRACE LinkRule name=Discount removed notification 2014-10-02 02:35:09,071 [main] TRACE Queue RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,071 [main] TRACE Queue Added 1 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,071 [main] TRACE BetaNode insert=1 stagedInsertWasEmpty=true 2014-10-02 02:35:09,071 [main] TRACE LinkNode notify=true nmask=1 smask=1 spos=1 rules=[RuleMem Discount awarded notification] 2014-10-02 02:35:09,071 [main] TRACE LinkSegment smask=2 rmask=3 name=Discount awarded notification 2014-10-02 02:35:09,071 [main] TRACE LinkRule name=Discount awarded notification 2014-10-02 02:35:09,071 [main] TRACE Queue RuleAgendaItem [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,071 [main] TRACE Queue Added 3 [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] Customer mark now has a shopping total of 120.0 2014-10-02 02:35:09,071 [main] TRACE Removing RuleAgendaItem [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,071 [main] TRACE Queue Removed 2 [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,071 [main] TRACE Rule[name=Discount removed notification] segments=2 TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,072 [main] TRACE 8 [NotNode(8) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,072 [main] TRACE Segment 1 2014-10-02 02:35:09,072 [main] TRACE 8 [NotNode(8) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,072 [main] TRACE rightTuples TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,073 [main] TRACE 9 [RuleTerminalNode(9): rule=Discount removed notification] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,073 [main] TRACE Segment 1 2014-10-02 02:35:09,073 [main] TRACE 9 [RuleTerminalNode(9): rule=Discount removed notification] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,073 [main] TRACE Removing RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,073 [main] TRACE Queue Removed 1 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,073 [main] TRACE Rule[name=Discount awarded notification] segments=2 TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,073 [main] TRACE 10 [JoinNode(10) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,073 [main] TRACE Segment 1 2014-10-02 02:35:09,073 [main] TRACE 10 [JoinNode(10) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,074 [main] TRACE rightTuples TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,074 [main] TRACE 11 [RuleTerminalNode(11): rule=Discount awarded notification] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,074 [main] TRACE Segment 1 2014-10-02 02:35:09,074 [main] TRACE 11 [RuleTerminalNode(11): rule=Discount awarded notification] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,074 [main] TRACE Fire "Discount awarded notification" [[ Discount awarded notification active=false ] [ [fact 0:7:874153561:874153561:7:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Discount@341a8659] [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] ] ] Customer mark now has a discount of 10 2014-10-02 02:35:09,074 [main] TRACE Removing RuleAgendaItem [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,074 [main] TRACE Queue Removed 1 [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,074 [main] TRACE Delete [fact 0:5:8996952:8996952:5:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Purchase@894858] 2014-10-02 02:35:09,074 [main] TRACE LinkSegment smask=2 rmask=3 name=Purchase notification 2014-10-02 02:35:09,074 [main] TRACE LinkRule name=Purchase notification 2014-10-02 02:35:09,074 [main] TRACE Queue RuleAgendaItem [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,074 [main] TRACE Queue Added 1 [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,075 [main] TRACE LinkSegment smask=2 rmask=3 name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,075 [main] TRACE LinkRule name=Apply 10% discount if total purchases is over 100 2014-10-02 02:35:09,075 [main] TRACE Queue RuleAgendaItem [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,075 [main] TRACE Queue Added 2 [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,075 [main] TRACE Added Apply 10% discount if total purchases is over 100 to eager evaluation list. Customer mark has returned the hat 2014-10-02 02:35:09,075 [main] TRACE Rule[name=Apply 10% discount if total purchases is over 100] segments=2 TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,075 [main] TRACE 12 [ AccumulateNode(12) ] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,075 [main] TRACE Segment 1 2014-10-02 02:35:09,075 [main] TRACE 12 [ AccumulateNode(12) ] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,075 [main] TRACE rightTuples TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,075 [main] TRACE 13 [RuleTerminalNode(13): rule=Apply 10% discount if total purchases is over 100] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,075 [main] TRACE Segment 1 2014-10-02 02:35:09,075 [main] TRACE 13 [RuleTerminalNode(13): rule=Apply 10% discount if total purchases is over 100] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,075 [main] TRACE Delete [fact 0:7:874153561:874153561:7:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Discount@341a8659] 2014-10-02 02:35:09,075 [main] TRACE LinkSegment smask=2 rmask=3 name=Discount removed notification 2014-10-02 02:35:09,075 [main] TRACE LinkRule name=Discount removed notification 2014-10-02 02:35:09,075 [main] TRACE Queue RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,075 [main] TRACE Queue Added 3 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,075 [main] TRACE UnlinkNode notify=true nmask=1 smask=0 spos=1 rules=[RuleMem Discount awarded notification] 2014-10-02 02:35:09,076 [main] TRACE UnlinkSegment smask=2 rmask=1 name=[RuleMem Discount awarded notification] 2014-10-02 02:35:09,076 [main] TRACE UnlinkRule name=Discount awarded notification 2014-10-02 02:35:09,076 [main] TRACE Queue RuleAgendaItem [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,076 [main] TRACE Queue Added 2 [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,076 [main] TRACE Rule[name=Purchase notification] segments=2 TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE 14 [JoinNode(5) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Purchase]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE Segment 1 2014-10-02 02:35:09,076 [main] TRACE 14 [JoinNode(5) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Purchase]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE rightTuples TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE 15 [RuleTerminalNode(6): rule=Purchase notification] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE Segment 1 2014-10-02 02:35:09,076 [main] TRACE 15 [RuleTerminalNode(6): rule=Purchase notification] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE Removing RuleAgendaItem [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,076 [main] TRACE Queue Removed 1 [Activation rule=Purchase notification, act#=2, salience=10, tuple=null] 2014-10-02 02:35:09,076 [main] TRACE Rule[name=Discount removed notification] segments=2 TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE 16 [NotNode(8) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE Segment 1 2014-10-02 02:35:09,076 [main] TRACE 16 [NotNode(8) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,076 [main] TRACE rightTuples TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE 17 [RuleTerminalNode(9): rule=Discount removed notification] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE Segment 1 2014-10-02 02:35:09,077 [main] TRACE 17 [RuleTerminalNode(9): rule=Discount removed notification] TupleSets[insertSize=1, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE Fire "Discount removed notification" [[ Discount removed notification active=false ] [ null [fact 0:1:1455177644:1455177644:1:DEFAULT:NON_TRAIT:org.drools.examples.shopping.ShoppingExample$Customer@56bc3fac] ] ] Customer mark now has a discount of 0 2014-10-02 02:35:09,077 [main] TRACE Removing RuleAgendaItem [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,077 [main] TRACE Queue Removed 1 [Activation rule=Discount removed notification, act#=0, salience=0, tuple=null] 2014-10-02 02:35:09,077 [main] TRACE Rule[name=Discount awarded notification] segments=2 TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE 18 [JoinNode(10) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE Segment 1 2014-10-02 02:35:09,077 [main] TRACE 18 [JoinNode(10) - [ClassObjectType class=org.drools.examples.shopping.ShoppingExample$Discount]] TupleSets[insertSize=0, deleteSize=0, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE rightTuples TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE 19 [RuleTerminalNode(11): rule=Discount awarded notification] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE Segment 1 2014-10-02 02:35:09,077 [main] TRACE 19 [RuleTerminalNode(11): rule=Discount awarded notification] TupleSets[insertSize=0, deleteSize=1, updateSize=0] 2014-10-02 02:35:09,077 [main] TRACE Removing RuleAgendaItem [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,077 [main] TRACE Queue Removed 1 [Activation rule=Discount awarded notification, act#=7, salience=0, tuple=null] 2014-10-02 02:35:09,077 [main] TRACE Removing RuleAgendaItem [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null] 2014-10-02 02:35:09,077 [main] TRACE Queue Removed 1 [Activation rule=Apply 10% discount if total purchases is over 100, act#=1, salience=0, tuple=null]Reference: Trace output with Drools from our JCG partner Mark Proctor at the Drools & jBPM blog....
jcg-logo

Java Code Geeks and ej-technologies are giving away FREE JProfiler Licenses (worth over $2000)!

Tired of having performance issues on your live servers? Then we have something especially for you! We are partnering with ej-technologies, creator of cool Java tools, and we are running a contest giving away FREE licenses for the award-winning all-in-one Java profiler, JProfiler. JProfiler is an all-in-one Java profiler that is easy to use and has advanced functionality for solving hard problems. JProfiler’s intuitive UI helps you resolve performance bottlenecks, pin down memory leaks and understand threading issues. To learn more about JProfiler, see http://www.ej-technologies.com/products/jprofiler/overview.html A fully functional evaluation is available from http://www.ej-technologies.com/download/jprofiler/filesWhy use JProfiler?Exceptional ease of use Database profiling for JDBC, JPA and NoSQL Excellent support for Java Enterprise Edition Higher level profiling data Stellar analysis of memory leaks Extensive QA capabilities Broadest support for technologies and tools Low overhead The powerful CPU profiler The integrated thread profilerEnter the contest now to win your very own FREE JProfiler Licence. There will be a total of 5 winners! In addition, we will send you free tips and the latest news from the Java community to master your technical knowledge (you can unsubscribe at any time). In order to increase your chances of winning, don’t forget to refer as much of your friends as possible! You will get 3 more entries for every friend you refer, that is 3 times more chances! Make sure to use your lucky URL to spread the word! You can share it on your social media channels, or even mention it on a blog post if you are a blogger! Good luck and may the force be with you! UPDATE: The giveaway has ended! Here is the list of the lucky winners! (emails hidden for privacy)ro…am@gmail.com cr…oi@yahoo.com de…ol@yahoo.co.uk ja…tv@gmail.com th…va@yahoo.com.brWe like to thank you all for participating to this giveaway. Till next time, Keep up the good work!...
jooq-logo-black-100x80

Don’t Miss out on Writing Java 8 SQL One-Liners with jOOλ or jOOQ

More and more people are catching up with the latest update to our platform by adopting functional programming also for their businesses. At Data Geekery, we’re using Java 8 for our jOOQ integration tests, as using the new Streams API with lambda expressions makes generating ad-hoc test data so much easier. However, we don’t feel that the JDK offers as much as it could, which is why we have also implemented and open-sourced jOOλ, a small utility library that patches those short-comings.   Note, we don’t aim to replace more sophisticated libraries like functionaljava. jOOλ is really just patching short-comings. Putting lambdas to work with jOOλ or jOOQ I’ve recently encountered this Stack Overflow question, which asked for streaming a result set with all columns into a single list. For example: Input +----+------------+------------+ | ID | FIRST_NAME | LAST_NAME | +----+------------+------------+ | 1 | Joslyn | Vanderford | | 2 | Rudolf | Hux | +----+------------+------------+ Output 1 Joslyn Vanderford 2 Rudolf Hux This is a typical school-book example for using functional programming rather than an iterative solution: Iterative solution ResultSet rs = ...; ResultSetMetaData meta = rs.getMetaData();List<Object> list = new ArrayList<>();while (rs.next()) { for (int i = 0; i < meta.getColumnCount(); i++) { list.add(rs.getObject(i + 1)); } } Truth is, the iterative solution isn’t all that bad, but let’s learn how this could be done with functional programming. Using jOOλWe’re using jOOλ for this example for a couple of reasons:JDBC didn’t really adopt the new features. There is no simple ResultSet to Stream conversion, even if there should be. Unfortunately, the new functional interfaces do not allow for throwing checked exceptions. The try .. catch blocks inside lambdas don’t exactly look nice Interestingly, there is no way of generating a finite stream without also implementing an Iterator or SpliteratorSo, here’s the plain code: ResultSet rs = ...; ResultSetMetaData meta = rs.getMetaData();List<Object> list = Seq.generate() .limitWhile(Unchecked.predicate(v -> rs.next())) .flatMap(Unchecked.function(v -> IntStream .range(0, meta.getColumnCount()) .mapToObj(Unchecked.intFunction(i -> rs.getObject(i + 1) )) )) .toList() So far, this looks about as verbose (or a bit more) than the iterative solution. As you can see, a couple of jOOλ extensions were needed here: // This generate is a shortcut to generate an // infinite stream with unspecified content Seq.generate()// This predicate-based stream termination // unfortunately doesn't exist in the JDK // Besides, the checked exception is wrapped in a // RuntimeException by calling Unchecked.wrapper(...) .limitWhile(Unchecked.predicate(v -> rs.next()))// Standard JDK flatmapping, producing a "nested" // stream of column values for the "outer" stream // of database rows .flatMap(Unchecked.function(v -> IntStream .range(0, meta.getColumnCount()) .mapToObj(Unchecked.intFunction(i -> rs.getObject(i + 1) )) ))// This is another convenience method that is more // verbose to write with standard JDK code .toList() Using jOOQ jOOQ has even more convenience API to operate on result records of your SQL statement. Consider the following piece of logic: ResultSet rs = ...;List<Object> list = DSL.using(connection) .fetch(rs) .stream() .flatMap(r -> Arrays.stream(r.intoArray())) .collect(Collectors.toList()); Note that the above example is using standard JDK API, without resorting to jOOλ for convenience. If you want to use jOOλ with jOOQ, you could even write: ResultSet rs = ...;List<Object> list = Seq.seq(DSL.using(connection).fetch(rs)) .flatMap(r -> Arrays.stream(r.intoArray())) .toList(); Easy? I would say so! Let’s remember that this example:Fetches a JDBC ResultSet into a Java Collection Transforms each record in the result set into an array of column values Transforms each array into a stream Flattens that stream into a stream of streams Collects all values into a single listWhew! Conclusion We’re heading towards exciting times! It will take a while until all Java 8 idioms and functional thinking will feel “natural” to Java developers, also in the enterprise. The idea of having a sort of data source that can be configured with pipelined data transformations expressed as lambda expressions to be evaluated lazily is very compelling, though. jOOQ is an API that encapsulates SQL data sources in a very fluent and intuitive way, but it doesn’t stop there. jOOQ produces regular JDK collections of records, which can be transformed out-of-the-box via the new streams API. We believe that this will drastically change the way the Java ecosystem will think about data transformation. Stay tuned for more examples on this blog!Reference: Don’t Miss out on Writing Java 8 SQL One-Liners with jOOλ or jOOQ from our JCG partner Lukas Eder at the JAVA, SQL, AND JOOQ blog....
agile-logo

Six Tips for Interviewing Scrum Masters, Part 1

People want to know the “secret sauce” for hiring Scrum Masters and agile coaches. I wish it was easy to provide a standard set of questions. Because your agile team is unique, your questions should be different. However, there are some common qualities, preferences, and non-technical skills among Scrum Masters. First, do a job analysis for your Scrum Master. I have met teams who needed an agile project manager because no one was in the same place. I have met teams who needed an account manager, because they were consultants. I wrote about this problem in Which “Scrum Master” Are You Hiring? I also did a potential job analysis for a servant leader/Scrum Master in What Do You Look for in a Servant Leader or a Scrum Master? The chances of this being the correct job analysis for your Scrum Master are not so good, given what I see in organizations. Tip 1: Define Your Scrum Master’s Deliverables Since every team and organization I work with is unique, you need to do your own job analysis. You do. For the sake of argument, let’s assume the Scrum Master has these deliverables:Coach team(s). (If you want to be a great Scrum Master, look at Michael James’ Scrum Master checklist. A great Scrum Master coaches one team.) Facilitate team meetings and Scrum rituals. Ensure information radiators are up to date. Looks at the team’s process and sees if the team need other radiators. Advocates for the team. Identifies and removes team impediments. Coaches on agile practices. Helps team see what they are doing to see how they can improve. Coaches on technical practices. Helps the team become self-sufficient.You are not going to ask questions about each of these deliverables. However, you would use these deliverables to create an audition. Tip 2: Define Your Scrum Master’s Essential Qualities, Preferences, and Non-Technical Skills Note that I said the essential qualities, preferences, and non-technical skills. Maybe your Scrum Master needs fewer than what I have below. Maybe you are starting a transition and your Scrum Master needs more. Maybe you need something different. You would use the essential qualities, preferences, and non-technical skills to create behavior-description questions:Initiative Flexibility Communications Resilience Determination Perseverance Ability to find another option Recognition of management power, but not intimidated by it Ability to use that powerNotice that these are all interpersonal skills. A Scrum Master works with people—people in the team, people in management, people across the organization. It’s all about the people. If you have desirable qualities, preferences, and non-technical skills, note them. If you have two candidates who are “equal,” you may decide to use the desirables to decide between the candidates. Tip 3: Define Your Scrum Master’s Essential Technical Skills I have trouble with with teams who need a Scrum Master who understands tools and technology. That’s missing the point of a servant leader. I understand Scrum Masters who understand the domain—that’s understanding the risks and helping management understand why they need to remove obstacles. But, if the Scrum Master is getting involved in the coding or the testing or the UX design (or whatever), the SM is not facilitating the entire team. If you define too many technical skills, the Scrum Master is not making sure the Product Owner is available to see the team’s progress on stories. The SM is not making sure the PO is making stories small. The SM is not making sure the team is delivering something of value every single day, or more often. The SM is not helping the team review their process if the SM is doing the technical work of the team. Be very careful if you have a SM who is a working member of the team. I say this in Hiring Geeks That Fit: Don’t ask people—managers or not—to work at the strategic and tactical levels. No one can. The tactical, day-to-day issues win. Always. Or, the strategic work wins. But they can’t both win. Never. A Scrum Master takes a more strategic look at the team’s work than a team member does. That’s because the SM facilitates the process. That’s by design.Reference: Six Tips for Interviewing Scrum Masters, Part 1 from our JCG partner Johanna Rothman at the Managing Product Development blog....
java-interview-questions-answers

Jar Hell made Easy – Demystifying the classpath with jHades

Some of the hardest problems a Java Developer will ever have to face are classpath errors: ClassNotFoundException, NoClassDefFoundError, Jar Hell, Xerces Hell and company. In this post we will go through the root causes of these problems, and see how a minimal tool (JHades) can help solving them quickly. We will see why Maven cannot (always) prevent classpath duplicates, and also:        The only way to deal with Jar Hell Class loaders The Class loader chain Class loader priority: Parent First vs Parent Last Debugging server startup problems Making sense of Jar Hell with jHades Simple strategy for avoiding classpath problems The classpath gets fixed in Java 9?The only way to deal with Jar Hell Classpath problems can be time-consuming to debug, and tend to happen at the worst possible times and places: before releases, and often in environments where there is little to no access by the development team. They can also happen at the IDE level, and become a source of reduced productivity. We developers tend to find these problems early and often, and this is the usual response:Let’s try to save us some hair and get to the bottom of this. These type of problems are hard to approach via trial and error. The only real way to solve them is to really understand what is going on, but where to start? It turns out that Jar Hell problems are simpler than what they look, and only a few concepts are needed to solve them. In the end, the common root causes for Jar Hell problems are:a Jar is missing there is one Jar too many a class is not visible where it should beBut if it’s that simple, then why are classpath problems so hard to debug? Jar Hell stack traces are incomplete One reason is that the stack traces for classpath problems have a lot of information missing that is needed to troubleshoot the problem. Take for example this stack trace: java.lang.IncompatibleClassChangeError: Class org.jhades.SomeServiceImpl does not implement the requested interface org.jhades.SomeService org.jhades.TestServlet.doGet(TestServlet.java:19)It says that a class does not implement a certain interface. But if we look at the class source: public class SomeServiceImpl implements SomeService { @Override public void doSomething() { System.out.println( "Call successful!" ); } }Well, the class clearly implements the missing interface! So what is going on then? The problem is that the stack trace is missing a lot of information that is critical to understanding the problem. The stack trace should have probably contained an error message such as this (we will learn what this means): The Class SomeServiceImpl of class loader /path/to/tomcat/lib does not implement the interface SomeService loaded from class loader Tomcat – WebApp – /path/to/tomcat/webapps/test This would be at least an indication of where to start:Someone new learning Java would at least know that there is this notion of class loader that is essential to understand what is going on It would make clear that one class involved was not being loaded from a WAR, but somehow from some directory on the server (SomeServiceImpl).What is a Class Loader? To start, a Class Loader is just a Java class, more exactly an instance of a class at runtime. It is NOT an inaccessible internal component of the JVM like for example the garbage collector. Take for example the WebAppClassLoader of Tomcat, here is it’s javadoc. As you can see it’s just a plain Java class, we can even write our own class loader if needed. Any subclass of ClassLoader will qualify as a class loader. The main responsibilities of a class loader is to known where class files are located, and then load classes on JVM demand. Everything is linked to a class loader Each object in the JVM is linked to it’s Class via getClass(), and each class is linked to a class loader via getClassLoader(). This means that: Every object in the JVM is linked to a class loader! Let’s see how this fact can be used to troubleshoot a classpath error scenario. How-To find where a class file really is Let’s take an object and see where it’s class file is located in the file system: System.out.println(service.getClass() .getClassLoader() .getResource("org/jhades/SomeServiceImpl.class"));This is the full path to the class file: jar:file:/Users/user1/.m2/repository/org/jhades/jar-2/1.0-SNAPSHOT/jar-2-1.0-SNAPSHOT.jar!/org/jhades/SomeServiceImpl.classAs we can see the class loader is just a runtime component that knowns where in the file system to look for class files and how to load them. But what happens if the class loader cannot find a given class? The Class loader Chain By default in the JVM, if a class loader does not find a class, it will then ask it’s parent class loader for that same class and so forth. This continues all the way up until the JVM bootstrap class loader (more on this later). This chain of class loaders is the class loader delegation chain. Class loader priority: Parent First vs Parent Last Some class loaders delegate requests immediately to the parent class loader, without searching first in their own known set of directories for the class file. A class loader operating on this mode is said to be in Parent First mode. If a class loader first looks for a class locally and only after queries the parent if the class is not found, then that class loader is said to be working in Parent Last mode. Do all applications have a class loader chain ? Even the most simple Hello World main method has 3 class loaders:The Application class loader, responsible for loading the application classes (parent first) The Extensions class loader, that loads jars from $JAVA_HOME/jre/lib/ext (parent first) The Bootstrap class loader, that loads any class shipped with the JDK such as java.lang.String (no parent class loader)What does the class loader chain of a WAR application look like? In the case of application servers like Tomcat or Websphere, the class loader chain is configured differently than a simple Hello World main method program. Take for example the case of the Tomcat class loader chain:Here we wee that each WAR runs in a WebAppClassLoader, that works in parent last mode (it can be set to parent first as well). The Common class loader loads libraries installed at the level of the server. What does the Servlet spec say about class loading? Only a small part of the class loader chain behavior is defined by the Servlet container specification:The WAR application runs on it’s own application class loader, that might be shared with other applications or not The files in WEB-INF/classes take precedence over everything elseAfter that, it’s anyones guess! The rest is completely open for interpretation by container providers. Why isn’t there a common approach for class loading across vendors? Usually open source containers like Tomcat or Jetty are configured by default to look for classes in the WAR first, and only then search in server class loaders. This allows for applications to use their own versions of libraries that override the ones available on the server. What about the big iron servers? Commercial products like Websphere will try to ‘sell’ you their own server provided libraries, that by default take precedence over the ones installed on the WAR. This is done assuming that if you bought the server you want also to use the JEE libraries and versions it provides, which is often NOT the case. This makes deploying to certain commercial products a huge hassle, as they behave differently then the Tomcat or Jetty that developers use to run applications in their workstation. We will see further on a solution for this. Common Problem: duplicate class versions At this moment you probably have a huge question: What if there are two jars inside a WAR that contain the exact same class? The answer is that the behavior is undetermined and only at runtime one of the two classes will be chosen. Which one gets chosen depends on the internal implementation of the class loader, there is no way to know upfront. But luckily most projects these days use Maven, and Maven solves this problem by ensuring only one version of a given jar is added to the WAR. So a Maven project is immune to this particular type of Jar Hell, right? Why Maven does not prevent classpath duplicates Unfortunately Maven cannot help in all Jar Hell situations. In fact, many Maven projects that don’t use certain quality control plugins can havehundreds of duplicate class files on the classpath (I saw trunks with over 500 duplicates). There are several reasons for that:Library publishers occasionally change the artifact name of a jar: This happens due to re-branding or other reasons. Take for example the example of the JAXB jar. There is no way Maven can identify those artifacts as being the same jar! Some jars are published with and without dependencies: Some library providers provide a ‘with dependencies’ version of a jar, which includes other jars inside. If we have transitive dependencies with the two versions, we will end up with duplicates. Some classes are copied between jars: Some library creators, when faced with the need for a certain class will just grab it from another project and copy it to a new jar without changing the package name.Are all class files duplicates dangerous? If the duplicate class files exist inside the same class loader, and the two duplicate class files are exactly identical then it does not matter which one gets chosen first – this situation is not dangerous. If the two class files are inside the same class loader and they are not identical, then there is no way which one will be chosen at runtime – this is problematic and can manifest itself when deploying to different environments. If the class files are in two different class loaders, then they are never considered identical (see the class identity crisis section further on). How can WAR classpath duplicates be avoided? This problem can be avoided for example by using the Maven Enforcer Plugin, with the extra rule of Ban Duplicate Classes turned on. You can quickly check if your WAR is clean using the JHades WAR duplicate classes report as well. This tool has an option to filter ‘harmless’ duplicates (same class file size). But even a clean WAR might have deployment problems: Classes missing, classes taken from the server instead of the WAR and thus with the wrong version, class cast exceptions, etc. Debugging the classpath with JHades Classpath problems often show up when the application server is starting up, which is a particularly bad moment specially when deploying to an environment where there is limited access. JHades is a tool to help deal it with Jar Hell (disclaimer: I wrote it). It’s a single Jar with no dependencies other than the JDK7 itself. This is an example of how to use it:new JHades() .printClassLoaders() .printClasspath() .overlappingJarsReport() .multipleClassVersionsReport() .findClassByName("org.jhades.SomeServiceImpl")This prints to the screen the class loader chain, jars, duplicate classes, etc. Debugging server startup problems JHades works works well in scenarios where the server does not start properly. A servlet listener is provided that allows to print classpath debugging information even before any other component of the application starts running. ClassCastException and the Class Identity Crisis When troubleshooting Jar Hell, beware of ClassCastExceptions. A class is identified in the JVM not only by it’s fully qualified class name, but alsoby it’s class loader. This is counterintuitive but in hindsight makes sense: We can create two different classes with the same package and name, ship them in two jars and put them in two different class loaders. One let’s say extends ArrayList and the other is a Map. The classes are therefore completely different (despite the same name) and cannot be cast to each other! The runtime will throw a CCE to prevent this potential error case, because there is no guarantee that the classes are castable. Adding the class loader to the class identifier was the outcome of the Class Identity Crisis that occurred in earlier Java days. A Strategy for Avoiding Classpath Problems This is easier said then done, but the best way to avoid classpath related deployment problems is to run the production server in Parent Lastmode. This way the class versions of the WAR take precedence over the ones on the server, and the same classes are used in production and in a developer workstation where it’s likely that Tomcat, Jetty or other open source Parent Last server is being used. In certain servers like Websphere, this is not sufficient and you also have to provide special properties on the manifest file to explicitly turn off certain libraries like for example JAX-WS. Fixing the classpath in Java 9 In Java 9 the classpath gets completely revamped with the new Jigsaw modularity system. In Java 9 a jar can be declared as a module and it will run in it’s own isolated class loader, that reads class files from other similar module class loaders in an OSGI sort of way. This will allow multiple versions of the same Jar to coexist in the same application if needed. Conclusions In the end, Jar Hell problems are not that low level or unapproachable as they might seem at first. It’s all about zip files (jars) being present / not being present in certain directories, how to find those directories, and how to debug the classpath in environments with limited access. By knowing a limited set of concepts such as Class Loaders, the Class Loader Chain and Parent First / Parent Last modes, these problems can be tackled effectively. External links This presentation Do you really get class loaders from Jevgeni Kabanov of ZeroTurnaround (JRebel company) is a great resource about Jar Hell and the different type of classpath related exceptions.Reference: Jar Hell made Easy – Demystifying the classpath with jHades from our JCG partner Aleksey Novik at the The JHades Blog blog....
java-interview-questions-answers

Java EE 7 with Angular JS – CRUD, REST, Validations – Part 2

This is the promised follow up to the Java EE 7 with Angular JS – Part 1. It took longer than I expect (to find the time to prepare the code and blog post), but it’s finally here! The Application The original application in Part 1 it’s only a simple list with pagination and a REST service that feeds the list data.        In this post we’re going to add CRUD (Create, Read, Update, Delete) capabilities, bind REST services to perform these operations on the server side and validate the data. The Setup The Setup is the same from Part 1, but here is the list for reference:Java EE 7 Angular JS ng-grid UI Bootstrap WildflyThe Code Backend – Java EE 7 The backend does not required many changes. Since we want the ability to create, read, update and delete, we need to add the appropriate methods in the REST service to perform these operations: PersonResource package com.cortez.samples.javaee7angular.rest;import com.cortez.samples.javaee7angular.data.Person; import com.cortez.samples.javaee7angular.pagination.PaginatedListWrapper;import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.ws.rs.*; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import java.util.List;@Stateless @ApplicationPath("/resources") @Path("persons") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class PersonResource extends Application { @PersistenceContext private EntityManager entityManager;private Integer countPersons() { Query query = entityManager.createQuery("SELECT COUNT(p.id) FROM Person p"); return ((Long) query.getSingleResult()).intValue(); }@SuppressWarnings("unchecked") private List<Person> findPersons(int startPosition, int maxResults, String sortFields, String sortDirections) { Query query = entityManager.createQuery("SELECT p FROM Person p ORDER BY " + sortFields + " " + sortDirections); query.setFirstResult(startPosition); query.setMaxResults(maxResults); return query.getResultList(); }private PaginatedListWrapper<Person> findPersons(PaginatedListWrapper<Person> wrapper) { wrapper.setTotalResults(countPersons()); int start = (wrapper.getCurrentPage() - 1) * wrapper.getPageSize(); wrapper.setList(findPersons(start, wrapper.getPageSize(), wrapper.getSortFields(), wrapper.getSortDirections())); return wrapper; }@GET public PaginatedListWrapper<Person> listPersons(@DefaultValue("1") @QueryParam("page") Integer page, @DefaultValue("id") @QueryParam("sortFields") String sortFields, @DefaultValue("asc") @QueryParam("sortDirections") String sortDirections) { PaginatedListWrapper<Person> paginatedListWrapper = new PaginatedListWrapper<>(); paginatedListWrapper.setCurrentPage(page); paginatedListWrapper.setSortFields(sortFields); paginatedListWrapper.setSortDirections(sortDirections); paginatedListWrapper.setPageSize(10); return findPersons(paginatedListWrapper); }@GET @Path("{id}") public Person getPerson( @PathParam("id") Long id) { return entityManager.find(Person.class, id); }@POST public Person savePerson(Person person) { if (person.getId() == null) { Person personToSave = new Person(); personToSave.setName(person.getName()); personToSave.setDescription(person.getDescription()); personToSave.setImageUrl(person.getImageUrl()); entityManager.persist(person); } else { Person personToUpdate = getPerson(person.getId()); personToUpdate.setName(person.getName()); personToUpdate.setDescription(person.getDescription()); personToUpdate.setImageUrl(person.getImageUrl()); person = entityManager.merge(personToUpdate); }return person; }@DELETE @Path("{id}") public void deletePerson(@PathParam("id") Long id) { entityManager.remove(getPerson(id)); } } The code is exactly as a normal Java POJO, but using the Java EE annotations to enhance the behaviour. @ApplicationPath("/resources") and @Path("persons") will expose the REST service at the url yourdomain/resources/persons (yourdomain will be the host where the application is running). @Consumes(MediaType.APPLICATION_JSON) and @Produces(MediaType.APPLICATION_JSON) accept and format REST request and response as JSON. For the REST operations:Annotation / HTTP Method Java Method URL Behaviour@GET / GET listPersons http://yourdomain/resources/persons Returns a paginated list of 10 persons.@GET / GET getPerson http://yourdomain/resources/persons/{id} Returns a Person entity by it’s id.@POST / POST savePerson http://yourdomain/resources/persons Creates or Updates a Person.@DELETE / DELETE deletePerson http://yourdomain/resources/persons/{id} Deletes a Person entity by it’s id.The url invoked for each operations is very similar. The magic to distinguish which operation needs to be called is defined in the HTTP method itself when the request is submitted. Check HTTP Method definitions. For getPerson and deletePerson note that we added the annotation @Path("{id}") which defines an optional path to call the service. Since we need to know which object we want to get or delete, we need to indicate the id somehow. This is done in the service url to be called, so if we want to delete the Person with id 1, we would call http://yourdomain/resources/persons/1 with the HTTP method DELETE. That’s it for the backend stuff. Only 30 lines of code added to the old REST service. I have also added a new property to the Person object, to hold a link to image with the purpose of displaying an avatar of the person. UI – Angular JS For the UI part, I’ve decided to split it into 3 sections: the grid, the form and the feedback messages sections, each with its own Angular controller. The grid is mostly the same from Part 1, but it did require some tweaks for the new stuff: Grid HTML <!-- Specify a Angular controller script that binds Javascript variables to the grid.--> <div class="grid" ng-controller="personsListController"> <div> <h3>List Persons</h3> </div><!-- Binds the grid component to be displayed. --> <div class="gridStyle" ng-grid="gridOptions"></div><!-- Bind the pagination component to be displayed. --> <pagination direction-links="true" boundary-links="true" total-items="persons.totalResults" items-per-page="persons.pageSize" ng-model="persons.currentPage" ng-change="refreshGrid()"> </pagination> </div> Nothing special here. Pretty much the same as Part 1. Grid Angular Controller app.controller('personsListController', function ($scope, $rootScope, personService) { // Initialize required information: sorting, the first page to show and the grid options. $scope.sortInfo = {fields: ['id'], directions: ['asc']}; $scope.persons = {currentPage: 1};$scope.gridOptions = { data: 'persons.list', useExternalSorting: true, sortInfo: $scope.sortInfo,columnDefs: [ { field: 'id', displayName: 'Id' }, { field: 'name', displayName: 'Name' }, { field: 'description', displayName: 'Description' }, { field: '', width: 30, cellTemplate: '<span class="glyphicon glyphicon-remove remove" ng-click="deleteRow(row)"></span>' } ],multiSelect: false, selectedItems: [], // Broadcasts an event when a row is selected, to signal the form that it needs to load the row data. afterSelectionChange: function (rowItem) { if (rowItem.selected) { $rootScope.$broadcast('personSelected', $scope.gridOptions.selectedItems[0].id); } } };// Refresh the grid, calling the appropriate rest method. $scope.refreshGrid = function () { var listPersonsArgs = { page: $scope.persons.currentPage, sortFields: $scope.sortInfo.fields[0], sortDirections: $scope.sortInfo.directions[0] };personService.get(listPersonsArgs, function (data) { $scope.persons = data; }) };// Broadcast an event when an element in the grid is deleted. No real deletion is perfomed at this point. $scope.deleteRow = function (row) { $rootScope.$broadcast('deletePerson', row.entity.id); };// Watch the sortInfo variable. If changes are detected than we need to refresh the grid. // This also works for the first page access, since we assign the initial sorting in the initialize section. $scope.$watch('sortInfo.fields[0]', function () { $scope.refreshGrid(); }, true);// Do something when the grid is sorted. // The grid throws the ngGridEventSorted that gets picked up here and assigns the sortInfo to the scope. // This will allow to watch the sortInfo in the scope for changed and refresh the grid. $scope.$on('ngGridEventSorted', function (event, sortInfo) { $scope.sortInfo = sortInfo; });// Picks the event broadcasted when a person is saved or deleted to refresh the grid elements with the most // updated information. $scope.$on('refreshGrid', function () { $scope.refreshGrid(); });// Picks the event broadcasted when the form is cleared to also clear the grid selection. $scope.$on('clear', function () { $scope.gridOptions.selectAll(false); }); }); A few more attributes are required to configure the behaviour of the grid. The important bits are the data: 'persons.list' which binds the grid data to Angular model value $scope.persons, the columnDefs which allow us to model the grid as we see fit. Since I wanted to add an option to delete each row, I needed to add a new cell which call the function deleteRow when you click in cross icon. The afterSelectionChanges function is required to update the form data with the person selected in the grid. You can check other grid options here. The rest of the code is self-explanatory and there is also a few comments in there. A special note about $rootScope.$broadcast: this is used to dispatch an event to all the other controllers. This is a way to communicate between controllers, since the grid, form and feedback messages have separate controllers. If everything was in only one controller, this was not required and a simple function call would be enough. Another possible solution if we want to keep the multiple controllers, would be to use Angular services. The used approach seems much cleaner since it separates the application concerns and does not require you to implement additional Angular services, but it might be a little harder to debug if needed. Form HTML <div class="form" ng-controller="personsFormController"> <!-- Verify person, if there is no id present, that we are Adding a Person --> <div ng-if="person.id == null"> <h3>Add Person</h3> </div> <!-- Otherwise it's an Edit --> <div ng-if="person.id != null"> <h3>Edit Person</h3> </div><div> <!-- Specify the function to be called on submit and disable HTML5 validation, since we're using Angular validation--> <form name="personForm" ng-submit="updatePerson()" novalidate><!-- Display an error if the input is invalid and is dirty (only when someone changes the value) --> <div class="form-group" ng-class="{'has-error' : personForm.name.$invalid && personForm.name.$dirty}"> <label for="name">Name:</label> <!-- Display a check when the field is valid and was modified --> <span ng-class="{'glyphicon glyphicon-ok' : personForm.name.$valid && personForm.name.$dirty}"></span><input id="name" name="name" type="text" class="form-control" maxlength="50" ng-model="person.name" required ng-minlength="2" ng-maxlength="50"/><!-- Validation messages to be displayed on required, minlength and maxlength --> <p class="help-block" ng-show="personForm.name.$error.required">Add Name.</p> <p class="help-block" ng-show="personForm.name.$error.minlength">Name must be at least 2 characters long.</p> <p class="help-block" ng-show="personForm.name.$error.maxlength">Name cannot be longer than 50 characters.</p> </div><!-- Display an error if the input is invalid and is dirty (only when someone changes the value) --> <div class="form-group" ng-class="{'has-error' : personForm.description.$invalid && personForm.description.$dirty}"> <label for="description">Description:</label> <!-- Display a check when the field is valid and was modified --> <span ng-class="{'glyphicon glyphicon-ok' : personForm.description.$valid && personForm.description.$dirty}"></span><input id="description" name="description" type="text" class="form-control" maxlength="100" ng-model="person.description" required ng-minlength="5" ng-maxlength="100"/><!-- Validation messages to be displayed on required, minlength and maxlength --> <p class="help-block" ng-show="personForm.description.$error.required">Add Description.</p> <p class="help-block" ng-show="personForm.description.$error.minlength">Description must be at least 5 characters long.</p> <p class="help-block" ng-show="personForm.description.$error.maxlength">Description cannot be longer than 100 characters.</p> </div><!-- Display an error if the input is invalid and is dirty (only when someone changes the value) --> <div class="form-group" ng-class="{'has-error' : personForm.imageUrl.$invalid && personForm.imageUrl.$dirty}"> <label for="imageUrl">Image URL:</label> <!-- Display a check when the field is valid and was modified --> <span ng-class="{'glyphicon glyphicon-ok' : personForm.imageUrl.$valid && personForm.imageUrl.$dirty}"></span><input id="imageUrl" name="imageUrl" type="url" class="form-control" maxlength="500" ng-model="person.imageUrl" required/><!-- Validation messages to be displayed on required and invalid. Type 'url' makes checks to a proper url format. --> <p class="help-block" ng-show="personForm.imageUrl.$error.required">Add Image URL.</p> <p class="help-block" ng-show="personForm.imageUrl.$invalid && personForm.imageUrl.$dirty">Invalid Image URL.</p> </div><div class="avatar" ng-if="person.imageUrl"> <img ng-src="{{person.imageUrl}}" width="400" height="250"/> </div><!-- Form buttons. The 'Save' button is only enabled when the form is valid. --> <div class="buttons"> <button type="button" class="btn btn-primary" ng-click="clearForm()">Clear</button> <button type="submit" class="btn btn-primary" ng-disabled="personForm.$invalid">Save</button> </div> </form> </div> </div> Here is the looks:A lot of codeis for validation purposes, but lets look into this a bit more in detail: each input element binds its value to person.something. This allows to model the data between the HTML and the Javascript controller, so we can write $scope.person.name in our controller to get the value filled in the form input with name, name. To access the data inside the HTML form we use the form name personForm plus the name of the input field. HTML5 have its own set of validations in the input fields, but we want to use the Angular ones. In that case, we need to disable form validations by using novalidate at the form element. Now, to use Angular validations, we can use a few Angular directives in the input elements. For this very basic form, we only use required, ng-minlength and ng-maxlength, but you can use others. Just look into the documentation. Angular assigns CSS classes based on the input validation state. To have an idea, these are the possible values:State CSS Onvalid ng-valid When the field is valid.invalid ng-invalid When the field is invalid.pristine ng-pristine When the field was never touched before.dirty ng-dirty When the field is changed.These CSS classes are empty. You need to create them and assign them styles in an included CSS sheet for the application. Instead, we’re going to use styles from Bootstrap which are very nice. For them to work, a few additional classes need to be applied to the elements. The div element enclosing the input needs the CSS class form-group and the input element needs the CSS class form-control. To display an invalid input field we add ng-class="{'has-error' : personForm.name.$invalid && personForm.name.$dirty}" to the containing input div. This code evaluates if the name in the personForm is invalid and if it’s dirty. It the condition verifies, then the input is displayed as invalid. Finally, for the form validation messages we need to verify the $error directive for each of the inputs and types of validations being performed. Just add ng-show="personForm.name.$error.minlength" to an HTML display element with a message to warn the user that the name input field is too short. Form Angular Controller // Create a controller with name personsFormController to bind to the form section. app.controller('personsFormController', function ($scope, $rootScope, personService) { // Clears the form. Either by clicking the 'Clear' button in the form, or when a successfull save is performed. $scope.clearForm = function () { $scope.person = null; // For some reason, I was unable to clear field values with type 'url' if the value is invalid. // This is a workaroud. Needs proper investigation. document.getElementById('imageUrl').value = null; // Resets the form validation state. $scope.personForm.$setPristine(); // Broadcast the event to also clear the grid selection. $rootScope.$broadcast('clear'); };// Calls the rest method to save a person. $scope.updatePerson = function () { personService.save($scope.person).$promise.then( function () { // Broadcast the event to refresh the grid. $rootScope.$broadcast('refreshGrid'); // Broadcast the event to display a save message. $rootScope.$broadcast('personSaved'); $scope.clearForm(); }, function () { // Broadcast the event for a server error. $rootScope.$broadcast('error'); }); };// Picks up the event broadcasted when the person is selected from the grid and perform the person load by calling // the appropiate rest service. $scope.$on('personSelected', function (event, id) { $scope.person = personService.get({id: id}); });// Picks us the event broadcasted when the person is deleted from the grid and perform the actual person delete by // calling the appropiate rest service. $scope.$on('deletePerson', function (event, id) { personService.delete({id: id}).$promise.then( function () { // Broadcast the event to refresh the grid. $rootScope.$broadcast('refreshGrid'); // Broadcast the event to display a delete message. $rootScope.$broadcast('personDeleted'); $scope.clearForm(); }, function () { // Broadcast the event for a server error. $rootScope.$broadcast('error'); }); }); }); For the form controller, we need the two functions that perform the operations associated with the button Clear and the button Save which are self-explanatory. A quick note: for some reason, Angular does not clear input fields which are in invalid state. I did found a few people complaining about the same problem, but I need to investigate this further. Maybe it’s something I’m doing wrong. REST services are called using save and delete from the $resource object which already implement the correspondent HTTP methods. Check the documentation. You can get a $resource with the following factory: REST Service // Service that provides persons operations app.factory('personService', function ($resource) { return $resource('resources/persons/:id'); }); The rest of the controller code, are functions to pickup the events created by the grid to load the person data in the form and delete the person. This controller also create a few events. If we add or remove persons, the grid needs to be updated so an event is generated requesting the grid to be updated. Feedback Messages HTML <!-- Specify a Angular controller script that binds Javascript variables to the feedback messages.--> <div class="message" ng-controller="alertMessagesController"> <alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</alert> </div> This is just the top section of the application, to display success or error messages based on save, delete or server error. Feedback Messages Angular Controller // Create a controller with name alertMessagesController to bind to the feedback messages section. app.controller('alertMessagesController', function ($scope) { // Picks up the event to display a saved message. $scope.$on('personSaved', function () { $scope.alerts = [ { type: 'success', msg: 'Record saved successfully!' } ]; });// Picks up the event to display a deleted message. $scope.$on('personDeleted', function () { $scope.alerts = [ { type: 'success', msg: 'Record deleted successfully!' } ]; });// Picks up the event to display a server error message. $scope.$on('error', function () { $scope.alerts = [ { type: 'danger', msg: 'There was a problem in the server!' } ]; });$scope.closeAlert = function (index) { $scope.alerts.splice(index, 1); }; }); This is the controller that push the messages to the view. Listens to the events created by the grid and the form controllers. The End Result Uff.. that was a lot of code and new information. Let’s see the final result:There is also a live version running in http://javaee7-angular.radcortez.cloudbees.net, thanks to Cloudbees. It may take a while to open if the cloud instances is hibernated (because of no usage). Resources You can clone a full working copy from my github repository and deploy it to Wildfly. You can find instructions there to deploy it. Should also work on Glassfish. Java EE – Angular JS Source Since I may modify the code in the future, you can download the original source of this post from the release 3.0. In alternative, clone the repo and checkout the tag from release 3.0 with the following command: git checkout 3.0. Check also:Java EE 7 with Angular JS – Part 1 Javascript Package Management – NPM – Bower – GruntFinal ThoughtsThe form validation kicks in right after you start typing. Angular 1.3 will have an on blur property to validate only after loosing focus, but I’m still using Angular 1.2.x. I have to confess that I found the validation code a bit too verbose. I don’t know if there is a way to simplify it, but you shouldn’t need to add each message validation to each input. A few things are still lacking here, like parameters sanitisation or server side validation. I’ll cover those in a next blog post.This was a very long post, actually the longest I’ve wrote on my blog. If you reached this far, thank you so much for your time reading this post. I hope you enjoyed it! Let me know if you have any comments.Reference: Java EE 7 with Angular JS – CRUD, REST, Validations – Part 2 from our JCG partner Roberto Cortez at the Roberto Cortez Java Blog blog....
java-interview-questions-answers

Kafka Benchmark on Chronicle Queue

Overview I was recently asked to compare the performance of Kafka with Chronicle Queue.  No two products are exactly alike, and performing a fair comparison is not easy.  We can try to run similar tests and see what results we get. This test is based on Apache Kafka Performance Results.         What was the test used? One area Kafka tests is multi-threaded performance.  In tests we have done, it is neither better or worse to use more more threads (up to the number CPUs you have).  We didn’t benchmark this here. All tests use one producer. Another difference, is that we flush to disk periodically by time rather than by count.  Being able to say you are never behind by more than X milli-seconds is often more useful than say 600 messages, as you don’t know how long those messages could have been waiting there.  For our tests, we look at flush periods of between 1 ms and 10 ms.  In Kafka’s tests, they appears to be every 3 ms approximately. The message size used was 200 bytes in each case, and we explored the difference writing batches of 1, 2, 5 and 10 messages at once made.  We also tried 200 messages in a batch and the performance was similar to batches of 10. We only tested writing to SSD disks for persistence.  Note: Chronicle is broker-less. The results The result of this test show you the message rate in terms of MB/s.  This is a reasonable way to describe the performance as the message size can vary, but you will get a similar amount of bandwidth, especially over 1 KB message sizes.device flush period (ms) 1 2 5 10ssd.ext4 1 236 MB/s 300 MB/s 340 MB/s 363 MB/sssd.ext4 3 378 MB/s 483 MB/s 556 MB/s 583 MB/sssd.ext4 10 495 MB/s 595 MB/s 687 MB/s 705 MB/stmpfs na 988 MB/s 1317 MB/s 1680 MB/s 1847 MB/sWe also tested “writing” to a tmpfs file system.  This is much faster as there is no actual writes to a device performed. Conclusions It isn’t possible to draw a direct comparison with Kafka as it is a broker based system as must send ever message over TCP.  Chronicle can replicate over TCP, however it doesn’t have to, and if you want to maximise performance you will use a high speed network, the fastest being the memory bus of your server. You can run similar tests and get exceptional results.  If you need to handle bursts of hundreds of MB/s, Chronicle may be a better solution.Reference: Kafka Benchmark on Chronicle Queue from our JCG partner Peter Lawrey at the Vanilla Java 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