Anda di halaman 1dari 126

Running Header: MAINTENANCE AT THE NORTH POLE

MAINTENANCE AT THE NORTH POLE: AN ASSESSMENT OF CONCURRENCY AND MAINTAINABILITY A THESIS SUBMITTED ON THE 10th OF MARCH, 2014 TO THE DEPARTMENT OF COMPUTER SCIENCE OF THE SCHOOL OF COMPUTER & INFORMATION SCIENCES OF REGIS UNIVERSITY IN PARTIAL FULFILLMENT OF THE REQUIREMENTS OF MASTER OF SCIENCE IN SOFTWARE ENGINEERING BY NATHAN NASS

APPROVALS

Advisor Name, Thesis Advisor

Ranked Faculty Name

Ranked Faculty Name

MAINTENANCE AT THE NORTH POLE Abstract This thesis explores some of the maintainability issues related to concurrent software through a comparative experiment. The primary issue that this thesis explores is the relationship between the syntactic evaluation of software maintainability, as seen in traditional software metrics and the semantic issues present in source code and design artifacts. In order to evaluate these areas, three separate concurrency paradigms were used to implement a common concurrency exercise, the Santa Claus Problem. The three versions of the software were all implemented in Java, but used different libraries to implement the concurrency paradigms. The three paradigms used were, the Java threading paradigm, the CSP paradigm in the library JCSP, and the actor model in the Akka library. This thesis analyzes the changes that occure in each version over the course of five iterations. Several of the most commonly available software metrics were applied to each version for each iteration and the versions were compared both in terms of the metrics themselves and in terms of the changes in these metrics over the five iterations. The results of this thesis suggest that traditional maintainability metrics are also applicable to concurrent software. The results also reveal several key trade-offs that can be used to evaluate the adoption of one concurrency paradigm over another.

MAINTENANCE AT THE NORTH POLE Acknowledgments I am greatful to the Regis faculty and class facilitators for introducing me to the ideas that have prompted the explorations in this thesis. I would also like to thank my faculty advisor, Dr. Douglas Hart for guiding me through the masters program at Regis University. Although it has been an arduous journey, I have always had clarity as to what I needed to do thanks to his advising. I would also like to thank my thesis advisor, Dr. Richard Blumenthal for his help in refining the scope and giving a new direction to the initial ideas that I had for this project. I would also like to thank my parents Arvid and Colleen Nass for their support in my decision to pivot in my career. I would not have made this decision without their help. Finally and most of all I would like to give my deepest gratitude to my wife, Ji Hyun. She has always been an encouragement to me and has pushed me to be better than I alone could ever be.

MAINTENANCE AT THE NORTH POLE Table of Contents !"#$%&'(#)%"*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,! -#.#/0/"#*%1*#2/3)3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,! 4/.3%"*1%$*3#'&5*%1*(%"('$$/"(5*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*6! 789:.".#)%"*%1*(%"('$$/"(5*9.$.&);03*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*<! 789:.".#)%"*%1*(%"('$$/"(5*9.$.&);0*)09:/0/"#.#)%"3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*=! 7>%:'#)%"?*@.)"#.)".A):)#5?*."&*B%"('$$/"(5*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*C! B2.9#/$*,+*D)#/$.#'$/*4/>)/E*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,,! B%"('$$/"(5*D)#/$.#'$/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,,! "#$%&'$(&%!)*!+)*+(&&%*+,!#*!-'.'!#*+/(0#*1!0%2#1*!3'$$%&*!/#$%&'$(&%!444444444444444444444444444444444444444444444444!55! "#$%&'$(&%!)*!678!'*0!678!#93/%9%*$'$#)*2!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!5:! "#$%&'$(&%!)*!;+$)&2!'*0!;+$)&!+)*+(&&%*+,!#93/%9%*$'$#)*2!444444444444444444444444444444444444444444444444444444444444444!5<! D)#/$.#'$/*%"*3%1#E.$/*0.)"#.)".A):)#5*0/#$)(3*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,F! B2.9#/$*G+*@/#2%&%:%;5*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*GG! !09:/0/"#.#)%"*%1*-."#.*B:.'3*9$%A:/0*3%:'#)%"3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*GG! -'.'!=>&%'02!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!?<! -678!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!?@! ;AA'!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!:<! @.)"#.)".A):)#5*!33'/3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*<,! 6>'*1%'B#/#$,!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!<5! H.#2/$)";*I.#.*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*<C! B2.9#/$*6+*4/3':#3*."&*J".:53)3*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*FK! @/#$)(3*1%$*@.)"#.)".A):)#5* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*FK! "#*%2!)C!6)0%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!DE! "#*%2!)C!6)0%!8%&!F%$>)0!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!D?! 6,+/)9'$#+!6)93/%G#$,!H;.%&'1%I! 4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!D:! 6)93/%G#$,!H;11%1'$%!7(9I!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!D<! ;CC%&%*$!6)(3/#*1!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!DD! JCC%&%*$!6)(3/#*1!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!DK! L.:3#/.&*@/#$)(3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*FM! L3%&'*02!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!DM! L3%&'$)&2!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!DM! N*#O(%!L3%&'*02!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!D@! N*#O(%!L3%&'$)&2!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!KE! "%*1$>!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!K5! P)+'B(/'&,!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!K?! P)/(9%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!K:! B2.9#/$*<+*H/"/$.:*J".:53)3*."&*B%"(:'3)%"3*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*=F! J".:53)3*%1*9.$.&);03*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*=F! Q%*%&'/!;*'/,2#2!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!KD! R%2#1*!'*0!"#B&'&,!S'2%0!;B2$&'+$#)*!)C!6)*+(&&%*$!J/%9%*$2!4444444444444444444444444444444444444444444444444444444444444!KK! ;$)9#+!'*0!R#2$&#B($%0!;/1)&#$>92!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!KM! 6)93/%G#$,!'*0!6)(3/#*1!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!K@! J".:53)3*%1*0.)"#.)".A):)#5*)"&)(.#%$3*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*MK! ;*'/,T'B#/#$,!'*0!=%2$'B#/#$,!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!UE! Q%*%&'/!;*'/,2#2!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!U?! B%"(:'3)%"3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*M<!

MAINTENANCE AT THE NORTH POLE J99/"&)8*J+*B%09:/#/*B%&/*%1*N$%;$.03* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*MM! 7>'&%0!6/'22%2!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!UU! N'$/*O.>.*P/$3)%"*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*MC! V)&$>8)/%!8'+A'1%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!UM! W#2>"#2$!8'+A'1%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!MD! 7%&.%&!8'+A'1%!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!MK! N$#/!8'+A'1%!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!MU! OB-N*P/$3)%"*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*CQ! -678V)&$>8)/%!8'+A'1%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!M@! W#2>"#2$8&)+%22!8'+A'1%!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!@D! 7%&.%&!8'+A'1%!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!@K! N$#/!8'+A'1%!44444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444!@M! JRR.*P/$3)%"*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,KK! ;AA'V)&$>8)/%!8'+A'1%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444! 5EE! W#2>"#2$!8'+A'1%!4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444! 5EM! 7%&.%&!8'+A'1%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444! 5E@! N$#/!8'+A'1%!444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444! 55E! 4/1/$/"(/3*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*,,G!

MAINTENANCE AT THE NORTH POLE Table of Figures Figure 1. Java Process Overview. ................................................................................................. 25! Figure 2. Santa's Friend State Flow .............................................................................................. 25! Figure 3. Waiting Room State Flow ............................................................................................. 26! Figure 4. Santa State Flow ............................................................................................................ 27! Figure 5. CSP Process and Channel Overview ............................................................................. 29! Figure 6. CSP Reindeer Process ................................................................................................... 30! Figure 7. CSP Elf Process ............................................................................................................. 32! Figure 8. CSP Waiting Room Process .......................................................................................... 32! Figure 9. CSP Santa Process ......................................................................................................... 34! Figure 10. Actor Version Overview with Connected Messages ................................................... 36! Figure 11. Reindeer Actor Model ................................................................................................. 38! Figure 12. Elf Actor Model........................................................................................................... 39! Figure 13. Waiting Room Actor Model ........................................................................................ 39! Figure 14. Santa Actor Model....................................................................................................... 40! Figure 15. Screenshot of Final Version ........................................................................................ 41! Figure 16. High Level Overview of User Interaction ................................................................... 44! Figure 17. Comparison of Lines of Code over Five Iterations ..................................................... 50! Figure 18. Comparison of Growth in Lines of Code over Five Iterations .................................... 51! Figure 19. Comparison of Lines of Code per Method over Five Iterations .................................. 52! Figure 20. Comparison of Growth in Lines of Code per Method over Five Iterations ................ 52! Figure 21. Comparison of Average Cyclomatic Complexity over Five Iterations ....................... 53! Figure 22. Comparison of Growth in Average Cyclomatic Complexity over Five Iterations ...... 53! Figure 23. Comparison of Complexity over Five Iterations ......................................................... 54! Figure 24. Comparison of Growth in Complexity over Five Iterations ........................................ 54! Figure 25. Comparison of Afferent Coupling over Five Iterations .............................................. 55! Figure 26. Comparison of Growth in Afferent Coupling over Five Iterations ............................. 55! Figure 27. Comparison of Efferent Coupling over Five Iterations ............................................... 57! Figure 28. Comparison of Growth in Efferent Coupling over Five Iterations.............................. 57! Figure 29. Comparison of Operands over Five Iterations............................................................. 58! Figure 30. Comparison of Growth in Operands over Five Iterations ........................................... 58! Figure 31. Comparison of Operators over Five Iterations ............................................................ 59! Figure 32. Comparison of Growth in Operators over Five Iterations ........................................... 59! Figure 33. Comparison of Unique Operands over Five Iterations ................................................ 60! Figure 34. Comparison of Growth in Unique Operands over Five Iterations .............................. 60! Figure 35. Comparison of Unique Operators over Five Iterations ............................................... 61! Figure 36. Comparison of Growth in Unique Operators over Five Iterations .............................. 61! Figure 37. Comparison of Length over Five Iterations................................................................. 62! Figure 38. Comparison of Growth in Length over Five Iterations ............................................... 62! Figure 39. Comparison of Vocabulary over Five Iterations ......................................................... 63! Figure 40. Comparison of Growth in Vocabulary over Five Iterations ........................................ 63! Figure 41. Comparison of Volume over Five Iterations ............................................................... 64! Figure 42. Comparison of Growth in Volume over Five Iterations .............................................. 64!

MAINTENANCE AT THE NORTH POLE

Introduction Statement of thesis In reality many things happen simultaneously. Almost all systems that are engineered are engineered on this basis. Roadways are engineered to accommodate many flows of traffic. Manufacturing systems are designed to split work into many stages that can happen at the same time at different locations. Airplanes are designed to control both wings at the same time. Humans also are always doing many things at once, such as breathing, seeing, typing, and listening. Software engineering has a specific field of study and practice that is dedicated to this way of engineering called concurrency. There are a plethora of tools, methodologies, and formal systems available for designing and creating concurrent software systems, some more common and easier to use than others. This thesis is not primarily concerned with these design and construction methodologies. Rather this thesis examines what happens after the system has already been designed, at the maintenance stage. According to Glass (2003) software maintenance consumes between 40 and 80 percent of a software project effort, and around 60 percent of this maintenance is directed towards adding new features to existing software. In his discussion on maintenance, Glass claims as a central fact that Understanding the existing product is the most difficult task in software maintenance (p. 120). While these may be general facts, what may be more important is examining exactly what types of things may optimize the maintenance process. This thesis focuses on one aspect of maintenance maintaining concurrent software. The main problem for developers is the complexity introduced by shared operations. Because of this, it is imperative that developers be able to design software in ways that are easy to reason about and maintain. Given this problem, there are many different paradigms for

MAINTENANCE AT THE NORTH POLE

concurrent programming that have arisen in recent years. Although the fundamental technical issues relating to these paradigms will need to be examined, issues such as performance and scalability are much more common in the literature than are qualitative issues such as how program design is affected differently by each paradigm, and how this in turn can reflect developer concerns in practice. This thesis aims to examine the design issues in adopting three different paradigms for concurrency: Concurrency using native Java concurrency primitive and design patterns (Zheng & Harper, 2010), actor based concurrency, here implemented in the Akka framework (Boner, 2012), and process based concurrency, implemented through JCSP (P. P. Welch, 2002). These paradigms will in particular be examined for how they affect the process of maintaining a piece of software, three implementations of the classic concurrency puzzle, The Santa Claus Problem. Software engineers recognize the difficultly of concurrent programming as primarily a problem of having tools that make concurrent software engineering a relatively straight-forward matter (Rajan, Kautz, & Rowcliffe, 2010). Indeed, one of the main problems is translating object-oriented designs into those that are safe and efficient when run concurrently (Grogono & Shearing, 2008).This fundamental problem results in many pervasive problems in the software engineering process as a whole. The purpose of this study is to explore the relationship between paradigms of concurrent implementation and more fundamental software engineering concerns, particularly software maintainability. For the purpose of this thesis, software maintainability will be defined primarily in terms of the some of the most important aspects of software quality as related to maintainability defined in ISO / IEC 25010 Systems and Software Quality Requirements and Evaluation (ISO, 2011). In particular this thesis examines analyzability, testability, and changeability. The analyzability and testability of a system have been correlated to particular quality metrics such as

MAINTENANCE AT THE NORTH POLE

complexity, coupling, and difficulty measures. In addition the changeability of a software system can be evaluated by examining the software as it changes. This thesis examines three parallel developments of the Santa Claus problem using three different concurrency paradigms over Five Iterations or iterations of evolution in which features are added to the software. Reason for study of concurrency The primary reason that software concurrency needs to be studied is captured in the title of the seminal article by Sutter The Free Lunch is Over (H. Sutter, 2005). This article recognizes that hardware improvements no longer will be adequate for overall improvement of the performance of the software. This is because current hardware relies on multiple processors or processors with multiple cores. In Sutter's words, programs can no longer simply ride the hardware wave of increasing performance unless they are highly concurrent (Sutter & Larus, 2005, para. 5). There are two primary software techniques that need to be mastered for taking advantage of this, parallelism and concurrency. While the fundamental concern of parallelism is using system resources to run parts of the program in parallel, harnessing multiple or multi-core processors, the fundamental concern of concurrency is with managing the shared aspect of the program when it is running in this way (Erb, 2013). Or in other words, concurrency is the decomposition of and integration of program parts that can run in parallel (IEEE, 2004). The standard tools that have been used to implement concurrent applications, particularly in the object-oriented C++ and Java worlds are threads and thread synchronization. The use of these techniques may increase the performance and scalability of the application, but they are notoriously difficult to manage. Concurrent programming using these synchronization

MAINTENANCE AT THE NORTH POLE

primitives is error-prone, with common programming errors such as nested monitor lockouts, missed or forgotten notifications, slipped conditions, etc. (Betin-Can & Bultan, 2004, p.1). Because of this difficultly in implementing concurrent software, if software firms do not investigate ways to make implementing concurrent software, they may end up sacrificing productivity, maintainability, and robustness for performance. However, the literature on software development is very clear that productivity and speed of development cycle is a fundamental factor in software firm success (Blackburn, Scudder, & Van Wassenhove, 2000). With both the pressure to develop high performance applications and have high performance teams, technologies and techniques for developing concurrent applications is a pressing concern. Explanation of concurrency paradigms One solution to the problem of concurrency is to work at a higher level of abstraction (Kulkarni et al., 2007). The benefit of this is that the language or library used can include features to reduce code complexity, common points of error, and inflexibility (Ghosh, Sheehy, Thorup, & Vinoski, 2011). This is the solution employed in two of the three paradigms that will be examined in this thesis, actor based concurrency and process-based concurrency. Actor based concurrency, which is most prominently featured in the programming languages Scala and Erlang, is based on the idea of units of a program that communicate by passing messages. According to the literature this paradigm can solve the concurrency problem in the following ways: On one side, it eliminates the need for synchronization of state (value). On the other side, the cost of copying such state (value) from one actor to another requires optimized and efficient ways of doing it, without excessively demanding intensive memory allocation and operations, like copy (Corra, 2009, p.23).

MAINTENANCE AT THE NORTH POLE

Process oriented concurrency, formally known as CSP or Communicating Sequential Processes, is not as ubiquitous as actor-based concurrency. However, process oriented concurrency has more academic backing and research, and it is based on a mathematical model, Hoares CSP process algebra (Welch & Pedersen, 2010, p.14). Process oriented programming is similar to the Actor based model in that it is oriented towards communication between networked units, but in process oriented programming the units are processes rather than actors. The primary benefits of process-oriented systems are that processes have complete control over their resources. This means that they cannot take control of another processes resources, but also that they can refuse to allow another process to interact with theirs. This is in contrast to objectoriented programming where state is shared and objects can take control of other objects state. The final paradigm to be examined is the use of and the improvement of object-oriented models of concurrency. This will primarily involve implementing design patterns and updated concurrency primitives to make concurrency more manageable and less error prone. As opposed to the overarching strategies of the above paradigms, each design pattern can solve a particular problem. This might be a very good solution if the developer knows the available patterns and needs the concurrent module to easily inter-operate with the rest of the software system. Zheng and Harper (2010) categorize 28 of these patterns into five categories based on their utility. To give an example of this approach, Static Locking Order is a design pattern that makes sure that the order of locks placed on resources does not lead to the corruption of those resources. Because of the ubiquity of design pattern education and use in industry, even with the development of technologies specifically designed for concurrency, this approach demands consideration. The amount of research and technology development centered on concurrency shows that it is an area that demands consideration. These practices are becoming mainstream in industry and in order for industry leaders to make informed decisions there needs to be an evaluation of

MAINTENANCE AT THE NORTH POLE

these tools from a software engineering perspective. This will ensure that developers are able to make high performance systems, while remaining highly performant themselves. Explanation of concurrency paradigm implementations This thesis limits the actual implementation mechanisms under study to three sets of technology. Akka has been chosen to represent the actor model. JCSP has been chosen to represent the CSP model. Finally Java's own native thread library has been chosen to represent thread-based concurrency. These technologies have been chosen first and foremost because they are all implementations that can be used in plain Java. Studying maintainability could be obscured if multiple non-equivalent programming languages, using different programming paradigms were introduced. Although the various solutions, particularly the actor model, eschew object orientation, they are all programmed in Java procedural style code. Akka is a "toolkit" for developing asynchronous, concurrent, and distributed systems using the actor model. Akka runs on the JVM (Java Virtual Machine) and it has API's available in two languages, Java and Scala. The underlying technology that is used to implement the system is a "Netty" based socket server (Roestenburg, Bakker, & Williams, 2013). It is used by a variety of well known clients including Amazon.com, UBS, VMWare, and Blizzard (Typesafe, 2012). The purported virtues of the tool kit are that it provides scalability, concurrency, and fault tolerance through a unified programming interface and conceptual model (Bonr, 2011). Akka also contains a testing framework, transaction support, and location transparency in a distributed environment (Gupta, 2012). JCSP is an implementation of CSP and the Pi calculus for the Java programming language as a library implementation. The stated goal of JCSP is to both enable the design of "layered networks of communicating processes" and to implement the theory of CSP in a

MAINTENANCE AT THE NORTH POLE

practical tangible way (Belapurkar, 2005). As opposed to Akka, JCSP has not sought or reached wide commercial acceptance. Rather it is used as a teaching framework and an area for academic research. The library has been developed at the University of Kent by professors Peter Welch and Paul Austin (Belapurkar, 2005). It has also been extended into robotics research in the form of JCSPre (Kerridge, Panayotopoulos, & Lismore, 2008). Furthermore it has been integrated into the Groovy parallel library, GPars (Codehaus, 2006). JCSP provides CSP constructs built on top of Java's concurrency primitives such as "sync, wait and notify" (Belapurkar, 2005). The fundamental programing construct is a process, which is a self-contained unit that contains both data and program logic. Processes only communicate through channels or in events (Welch & Austin, 2013). The most significant aspect of this type of design, as opposed to an actor model, is that it is synchronous (Cox, 2013). The principle virtues and goals of JCSP are to simplify the specification and implementation of concurrent systems, to achieve a high level of performance, and to be able to be logically and mathematically verifiable (Welch, 2002). The most well known, commonly used, and well documented of the three paradigms is thread-based concurrency. The JVM was initially designed with concurrency as a concern. In particular it was on of the first languages to introduce multi-threading as a way of designing and implementing concurrent programs (Jenkov, 2013). Throughout the history of the language the concurrent functionality has been further refined. The JSR-166 package standardized and incorporated a set of tools, atomic variables, and collections that gave Java programmers higher level constructs for writing concurrent classes (Goetz, 2004). Java 7 introduced the fork / join framework, which simplifies work sharing in a thread pool and over multiple processors. The goals of the Java concurrency constructs is both to improve the performance and throughput of an application as well as to influence the design of complex applications.

MAINTENANCE AT THE NORTH POLE

According to Goetz (2006) Java threads allow tasks of the same type to be grouped according to threads rather than being lumped together in the same class or thread of execution. Although all of the tools above have a similar goal of simplifying the design an implementation of concurrent applications, designing concurrent programs is still relatively difficult in comparison to sequential programs, if for no other reason than that concurrent programs signify a higher level of complexity in program logic in general. Furthermore, it is not yet conclusively accepted which paradigm is most useful according to particular situations. Although documentation and some amount of research has been dedicated to each of the above frameworks, they have not been compared in terms of how they affect application design, and in particular how these design decisions affect application maintainability. Evolution, Maintainability, and Concurrency As software has increased in complexity and size, the topic of software evolution has become an increasingly important topic to both software businesses and researchers. While initially software systems were view to be largely static, with only bug fixes being deployed after the initial release of a major version, now many companies may release several changes per day in a practice called continuous delivery (Humble & Farley, 2011; Mens & Demeyer, 2008). Now most engineers view malleability as a fundamental quality of software and design systems with this as a primary goal. Some software systems, known as E-type systems, must continuously change or they are perceived to decline in quality (Lehman, 1996). Software maintenance and software evolution may seem to be separate concepts, and some companies will separate between what are viewed as enhancements and what is viewed as maintenance. In reality the two categories overlap both in terms of practice and in related concepts that it may not make sense to distinguish between them. In particular Lehman and

MAINTENANCE AT THE NORTH POLE

Ramil (2002) argue that in an e-type of system evolution is maintenance because it maintains the expectations that are held by stakeholders about a system, whether it is improved performance, an updated interface, a new feature, or an adjustment of an existing feature. Glass (2003) writes about the 60 / 60 law of software engineering, which refers to the percentage of time spent in maintenance and the percentage of maintenance time spent in enhancements. Because the concepts of maintenance and evolution have become so integral to the software process and take such a large percentage of the development resources, many in management and in engineering have attempted to define a comprehensive science that defines software quality in terms of maintainability. One of the key ways that software companies have found to continuously evaluate the quality and maintainability of software is through the use of software metrics. Metrics are used as a way to compare the quality of a system, to allocate resources to maintenance tasks, and to evaluate evolution over time. The most basic metric is probably the Lines of Code metric, which simply describes the growth of a software system, but does not necessarily evaluate its quality. The most common metrics are those defined by Halstead, Chidamber & Kemerer, and McCabe (Chidamber & Kemerer, 1994; Halstead, 1977; McCabe, 1976). These metrics can be found in both analysis tools such as Sonar (Papapetrou & Campbell, 2013) or in integrated development environments such as Eclipse. One area that has not been evaluated in terms of evolution and maintainability is concurrent programming. In particular, this thesis addresses two aspects of software evolution that are not yet well understood. The first is what types of changes will need to be made in the course of performing maintenance activities on concurrent software. The other is whether wellknown software maintainability metrics can be used in a meaningful way to evaluate the

MAINTENANCE AT THE NORTH POLE

10

evolution and quality of a software system, or whether they hold any predictive value at the outset of a software project that is concurrent in nature.

MAINTENANCE AT THE NORTH POLE Chapter 2. Literature Review

11

The following literature review is intended to do two things. The first is to show the sources that were necessary in understanding the concepts that allowed for the experiment and interpretation of results in this thesis. The second is to show that even though both the development of both higher-level concurrency paradigms and the use of software metrics are intended to increase programmer productivity and software maintainability, these two areas do not have a common criterion for evaluation. This thesis attempts to develop this common criterion by viewing concurrency paradigms in terms of maintainability metrics and maintainability metrics in terms of concurrency in practice. The first half of this chapter examines literature on the concurrency paradigms used in this thesis. The second examines literature on the metrics for maintainability used in this thesis. Concurrency Literature Literature on concurrency in Java including design pattern literature One of the most commonly used language level concurrency implementations is in the Java programming language. The literature in this area is highly developed including book length discussions of concurrency best practices (Goetz et al., 2006; Lea, 2000) as well as many individual papers that range from concurrency JUnit testing (Ricken & Cartwright, 2010) to concurrency design patterns (D. C. Schmidt & Cranor, 1995). In terms of the study of developer best practices with concurrency the area of design patterns is a very profitable area. Design patterns became an important area of programming practice with the publication of Gamma, Helms, Johnson, & Vlissides (1994) seminal work Design Patterns: Elements of Reusable Object-Oriented Software. This work has motivated many book length works cataloging and teaching design patterns. Concurrency has been important in these works as well.

MAINTENANCE AT THE NORTH POLE

12

The commonly referenced and taught work Patterns of Enterprise Architecture (Fowler, 2002) includes one chapter dedicated to concurrency patterns. With the proliferation of patterns, it may be difficult for individual practitioners and researchers to evaluate them as a whole. Harper and Zheng (2010) present 28 design patterns in a question and answer format in order to help the reader quickly recognize and choose patterns for developing concurrent applications. This paper consists of a taxonomy of common concurrency goals and problems and places each pattern into these categories. The literature is also replete with many papers dedicated specifically to individual patterns. Betin-Can and Bultan (2004) develop a design pattern called the Concurrency Controller which encapsulates the variables and actions required for concurrency control and also serves as a specification of the synchronization policy (p. 2) The most prolific and widely varied examination of patterns for concurrency in individual research papers is in the work of Schmidt. This work includes patterns such as the Active Object pattern, which decouples method execution from method invocation in order to simplify synchronized access to an object that resides in its own thread of control (Lavender & Schmidt, 1995, p.1) or the Thread-Specific Storage pattern, which allows multiple threads to use one logically global access point to retrieve thread-specific data without incurring locking overhead for each access. (Schmidt, Harrison, & Pryce, 1997, p.1) A unique approach to the notion of design patterns in concurrency is taken by Rajan, Kautz, and Rowcliffe (2010). They contend that design patterns in general are good for concurrency because they help to enforce modularity and they suggest points in the program that concurrency can be implemented without posing a threat to the programs integrity. Taken as a whole the literature on design patterns shows an approach to concurrency that gives best practices for implementation based on the specific situation encountered to outcome desired.

MAINTENANCE AT THE NORTH POLE

13

Both Graham (Graham, 2002) and Norvig (Norvig, 1996) make the claim however that design patterns are evidence of a missing aspect of the programming language under use. Because of this languages have made use of a number of higher-level constructs for implicitly managing concurrency. Literature on CSP and CSP implementations The second paradigm under consideration is the process-oriented concurrency paradigm. Process oriented concurrency is concurrency that is based on the computer science theory of communicating sequential processes (CSP). This theory was first explicated by its developer Hoare in the paper Communicating Sequential Processes (1978). Hoare's contention was that like repetition and conditional control structures have achieved a nearly universal status in mainstream computer languages, primitives for managing concurrency should also be a part of these basic language features. Although his paper outlines the basic theory of how this would be implemented, this idea was not implemented in mainstream languages. Even so, it has continued as an area of research, and has much academic literature devoted to the theory. Two book length treatments exist (Hoare, 1985; Roscoe, 1997) The most extensive treatment of the subject as it relates to practical programming concerns is Sampson's PhD. Dissertation Process-Oriented Patterns for Concurrent Software Engineering (2010). Significant paper length treatments of the subject from a software engineering perspective are Welch and Pederson (2010) and Gorono and Shearing (2008). Grogono and Shearing described the necessity of developing a programming language that is oriented towards concurrency and argued that a process-oriented language is the best way to do that. They develop a language, Erasmus, to demonstrate this concept. Welch on the other hand uses process-oriented technology to solve the basic concurrency problem called the Santa Claus problem (described in

MAINTENANCE AT THE NORTH POLE

14

Chapter 3). Welch and Pederson apply the occam-pi programming language, which is an implementation of process-oriented ideas, to this problem to demonstrate this language's concurrency features. This paper provides both implementation details in the occam-pi language, and a theoretical analysis of both the solution and of process-oriented programming as a whole. Literature on Actors and Actor concurrency implementations The third paradigm considered in this literature review is the actor paradigm. Like the literature on CSP, the litureature on the actor paradigm ranges from foundational and theoretical workds to those examining practical considerations of program implementation. Hewitt, Bishop, and Seiger first (Hewitt, Bishop, & Steiger, 1973) introduced the notion of actors in the foundational paper A universal modular ACTOR formalism for artificial intelligence defining an actor as an active agent which plays a role on cue according to a script (p. 235) Agha and Hewitt also (Agha & Hewitt, 1985) extended this idea to concurrency in programming. They based the application of the actor model to concurrency on the requirements that the model implement shared resources, dynamic reconfigurability and inherent parallelism (p. 3). With this theoretical basis this paradigm has been applied to a number of language implementations. Corra (2009) surveys this history and a number of implementations of the actor model. He describes the most significant implementations as Erlang, Scala, Killim, and the Microsoft CCR/DSS framework. Another language survey of the actor model is Karmani, Shali, and Agha (2009). This paper particularly focuses on the implementations on the Java Virtual Machine (JVM), meaning that they are compatible to some degree with a Java platform and code base. Among the characteristics of actors defined in this paper are state encapsulation, safe messaging, fair scheduling, location transparency and mobility (pp. 2-4). The JVM

MAINTENANCE AT THE NORTH POLE

15

languages Scala, Kilim, JavAct, ActorFoundry and SALSA are evaluated for their adherence to these principles of the actor model. More in-depth coverage of specific actor based concurrency issues is also becoming more common in the literature. Erb (2013) in his PhD. dissertation gives an examination of the merits of various actor primitives in the JVM language Scala. Although he is positive about the actor model in general, he writes about the limitation that the JVM poses to a more full-fledged actor implementation. Haller (2012) also gives an in-depth coverage of the Scala implementation of actors. He describes the five main requirements that directed the Scala implementation and also gives coverage of how the actor model is made available through the programming interface. In addition to Scala actors, Haller covers the Akka implementation of actors, which is a third party implementation available to Scala developers. The Scala concurrency model, in particular the Scala actor model, is given a thorough evaluation by Wiebusch, Fishbach, Latoschik, and Tramberend (2012). They conclude that Scala, as a language, is particularly good in regards to the software engineering principles of reusability and extensibility, while the actor model implementation was good with regards to the application's scalability. Literature on software maintainability metrics The second half of this literature review considers the literature on software maintainability and maintainability metrics. In an assessment of software quality, the top reason that quality should be valued at least as highly as program functionality or the timeliness of delivery is that it may be difficult to modify or maintain programs of low quality (Boehm, Brown, & Lipow, 1976). The problem that is tackled in much of the literature on software maintainability is finding a way to measure the maintainability of a software system that is nonsubjective and automatable. In a survey of software engineering firms Broy, Deissneboek, and

MAINTENANCE AT THE NORTH POLE

16

Pizka (2006) found that only 20 percent of firms evaluated software maintainability as a measure of quality, and those that did lacked a common criteria for doing so. Subjective assessment of maintainability leads to situation where software is replaced in order to make up for a lack of maintainability in legacy systems, but the result is no more maintainable (Broy, Deissenboeck, & Pizka, 2006) The literature in this area has been developing since the 1970s. Much of the literature is written in response of the pioneering work of McCabe (1976), Halstead (1977) , and later to Chidamber and Kemerer (1994). The literature can be divided basically in to literature that expands on or restates the initial premise of these researchers and literature that evaluates its use specifically for measuring maintainability. McCabe's complexity metric (McCabe, 1976), or "cyclomatic complexity" is a measure of the number of ways that a piece of code could be executed. This metric was developed in order to accomplish two goals. The first would be to set a desirable complexity number that would control the growth of complexity in software projects. The second would be to create and assess test plans for software. McCabe also demonstrates an early use of automated code analysis in order to calculate metrics for a code example (ibid). Cyclomatic complexity and its variants are calculated based on rules for logical branching. Depending on the researcher varying values are assigned to constructs such as if else statements, case statements, and and / or additions to the conditional statement. This metric is mainly used in assessing the maintainability and testability of a software system, and has empirically shown correlation with programmer productivity during the maintenance cycle (Gill & Kemerer, 1991). Halstead developed the theory of Software Science as a way of providing measurable assessments of a piece of software (Halstead, 1977). In Halstead's metrics all software quality is

MAINTENANCE AT THE NORTH POLE

17

a result of the number and relationship between operands and operators (Al Qutaish & Abran, 2005). Although at times and in certain languages, the difference between the two is ambiguous, in a simple example an operator can be thought of as the mathematical equivalent, an addition symbol or assignment operator. The operands then would constitute the other elements, like function names, class names, parameters, or variables. The basic constituents of his software system are the number of operands, number of unique operands, number of operators, and number of unique operators. From these the analysis of program length, volume, vocabulary, and difficultly can be accomplished. Although foundational, some of Halstead's metrics and assumptions about software science can be criticized. For example, the metrics for program level, program difficulty, and program effort all require that practitioners share an assumption about the minimum number of operators necessary for a program (Bailey & Dingee, 1981). Nevertheless, Halstead's metrics are used in many assessments of software maintainability. Coleman et al. (1994) have pointed to the usefulness of the Halstead metrics in forming maintainability indexes. Others have made the claim that Halstead's metrics do not necessarily correspond to software maintainability (Berns, 1984) The alternative given requires an assessment of the program vocabulary, which is equally subjective but much less universally useful because it assigns weight to the difficultly of using specific constructs in programming languages, for example Fortran. Chidamber and Kemerer (1994) have developed an updated set of software metrics for object-oriented software. Whereas Halstead and McCabe largely measured concerns in the developing structured software development movement, Chidamber and Kemerer developed ways to measure the growth and relationship of interrelated objects and classes. The primary metrics in their suite are: Weighted Methods per Class, Depth of Inheritance, Number of Children, Coupling between Classes, Response for a Class, and Lack of Cohesions of Methods.

MAINTENANCE AT THE NORTH POLE

18

The Chidamber and Kemerer metrics have been evaluated and found to be able to predict the maintainability of a software project (Li & Henry, 1993). The Chidamber and Kemerer metrics can be classified as showing different types of balance in a software system, which indicates good overall design (Lanza & Marinescu, 2006). The most relevant metrics to maintainability in this metrics suite seems to be the coupling metric. This has also been studied in a variety of contexts. In a study of several open source projects De Souza and Maia conducted a comparative analysis of the rate of coupling based on the category of software (2013). They discovered that the game category was the most highly coupled, whereas the programmer tools category was the least highly coupled. They have suggested that further comparison studies should be done on coupling metrics using different types of categories such as programming language. Finally a variety of aggregates of the above metrics have been used to develop overall maintainability indexes for software systems. For example, in an assessment of software maintainability indexes researchers found that the combination of Halstead's effort metric combined with cyclomatic complexity and lines of code used by Hewlett-Packard was similar to the assessment given by expert engineers about a software system (Coleman, Ash, Lowther, & Oman, 1994). Kaur and Singh (2011) have formed maintainability indexes that are based upon aggregates of traditional metrics as well as experimental metrics based on neural networks. Jeet, Dhir, and Verma (2012) on the other hand use statistical methods, particular Bayesian logic to evaluate maintainability base on the decomposition of a maintainability model into nodes that can have rules associated with them. Although there are many theories and metrics that have been put forth in the literature, the literature that evaluates the practical application of these is largely divided. Software metrics have been assessed in a variety of situations and for a variety of use cases, in general they have been found be useful in giving a overview of software quality, but have also been criticized as

MAINTENANCE AT THE NORTH POLE

19

ignoring contextual information (Harrison, Magel, Kluczny, & DeKock, 1982). Kauer and Singh (2011) have assessed the relative value of various metrics in evaluating software maintainability. They have found a negative correlation between software maintainability and software complexity and the Halstead measures of length and volume. In a study of the accuracy of both McCabe's and Halstead's metrics in relation to programmer performance in maintaining a body of software researchers found that the metrics did provide a level of accuracy in determining actual programmer effort (Curtis, Sheppard, Milliman, Borst, & Love, 1979). Riaz, Mendes, and Tempero (2009) take a broad overview of the subject of maintainability by examining the applicability of various maintainability metrics and models. They find that most metrics are applicable to the standard definition of maintainability and that the most common measures of maintainability are size, complexity and coupling (p. 374). Finally the primary benefit of metrics is the ability to evaluate a software system on a regular basis in a way that is apart from human judgment (Bouwers, Correia, Deursen, & Visser, 2011). However, many researchers make the claim that it is not necessarily beneficial to remove human judgment from the process of assessing software quality. Broy et al. (2006) have found that because most of the significant aspects of software quality are semantic rather than syntactic, the benefits of using a software metric to determine true quality are minimal. Software complexity measures have also been criticized as having a damaging effect on software quality. This is because the complexity metric has been applied without a particular goal in mind and has been has been applied without proper testing for validity in the area of use (Kearney, Sedlmeyer, Thompson, Gray, & Adler, 1986). There are also cases in which software metrics may give unintuitive results. For example in comparing the cyclomatic complexity of a well structured program versus an unstructured program researchers found that although the unstructured program exhibited visual complexity it

MAINTENANCE AT THE NORTH POLE

20

registered lower on the metric because the metric was designed to measure the complexity of logical branching (Elshoff & Marcotty, 1978). Software metrics have also been criticized as ignoring contextual information (Harrison, Magel, Kluczny, & DeKock, 1982). In response to these criticisms practitioners have suggested a more balanced approach that allows metrics to be used, but also goal directed and contextualized. The Goal Question Metrics (GQM) approach (Van Solingen, Basili, Caldiera, & Rombach, 2002) describes a way for software metrics to be applied in a meaningful way for organizations. This approach is based on the idea that without a directed goal and context for continually understanding metrics, they will not be actionable for an organization. Thus there is a conceptual level (The Goal), an organizational level (The Question) and a quantitative level (The Metric) for a GQM process. Interestingly, in the GQM method metrics can be both objective and subjective. This is related to the dependency of a metric on a specific viewpoint. For example, the readability of a piece of code could be quantified through survey or interview responses, but would be subjective. However the dependencies in a software system could have an objective metric because it would not depend on any particular view. This literature review suggests that there is a gap in the literature between literature focused solely on concurrency paradigms aimed to improve things such as programmer productivity and software maintainability and the literature that purports to show how to actually measure what makes software maintainable. This thesis is not intended to settle the debate, either on what constitutes appropriate measurements for software maintainability or on which concurrency methodology is the most maintainable. Rather it is intended to be a sort of bridge between the two fields of literature. It describes how useful the commonly available current software metrics are at predicting software evolution in concurrent systems. It also attempts to

MAINTENANCE AT THE NORTH POLE

21

ground claims that using a certain concurrency paradigm can improve programmer productivity in the science of software measurement.

MAINTENANCE AT THE NORTH POLE

22

Chapter 3. Methodology The methodology of this thesis is divided in to three parts. The first is the methodology for building the software systems that the experiments were conducted on. This will involve an overview of the problem space and an in depth description of the architecture of each solution. The second describes the way that this system was modified as an experiment in software maintenance of a concurrent system. The third part describes the way that the system was measured using currently available tools. Implementation of Santa Claus problem solutions The methodology employed in this thesis is the constructivist methodology. First of all each paradigm will be used to solve a common concurrency problem, The Santa Claus problem. The Santa Claus problem was developed by Trono (1994). However a very good statement of the problem can be found in Downey (2005). The basic outline of the problem is that Santa sleeps until he is awakened by a group of either elves or reindeer. There are nine reindeer and ten elves in the program. In order to wake Santa a group of either three elves or all nine reindeer must gather. If Santa awakes and both groups are waiting, then he must go with the reindeer. When with the reindeer Santa hitches the reindeer to the sleigh, delivers gifts, and then releases the reindeer. While with the elves Santa welcomes the elves, consults on toy building, and then sends the elves back. After meeting with either group, Santa returns to sleep, and the group is release to start the process again. There are some pitfalls that are easy to fall into if the algorithm is not implemented correctly: One group interrupts Santa while he is with the other group.

MAINTENANCE AT THE NORTH POLE Elves are able to join the group while in the process of meeting with Santa. Members of a group do not leave when finished. Santa goes to sleep before all of the activities are finished. Not all of the members of the group accomplish a task.

23

This problem is a very good problem for studying maintainability because it is a wellformulated problem that has a number of published solutions that maintainability can be measured against. A wide range of solutions in the literature, particularly from CSP, but also from concurrency paradigms such as Join Calculus (ie. Polyphonic C#) have been devoted to the problem. Also the problem is purely related to concurrency problems rather than problems in parallelization. In other words the concurrency in the problem is motivated by correctness rather than by a need to optimize parallel resources. It could be considered as primarily a synchronization problem. Although there are many solutions, there are none that strictly use the author's chosen platforms, which are pure Java, based on the Java.utils.concurrent package, JCSP, and Akka for Java. (The most well known solutions are discussed in: Ben-Ari, 1998; Benton, 2003; Hurt & Pedersen, 2008; Jones, 2007; Kerridge, 2008; Trono, 1994; Welch & Pedersen, 2010.) Two of the solutions presented in this thesis, the pure Java and the Akka solution, are completely original, while the JCSP version borrows the CSP channels and algorithms from Kerridges solution in Groovy (2008), but rewritten in Java. The author was equally inexperienced in all of the concurrency paradigms at the outset, so there is little chance that there will be a variance in quality based on programmer knowledge.

MAINTENANCE AT THE NORTH POLE Java Threads

24

The Java version makes use of a few basic classes1, and the workflow is depicted in Figure 1. The objects for reindeer and elves both use the class SantasFriend are instantiated into individual threads. The waiting room and stable objects are instantiated each in a separate thread. Santa is also instantiated in another thread. The reindeer, elves, and Santa hold references to the waiting room or stable. The reindeer and elves attempt to enter the stable or the waiting room. Once they enter the waiting room they are placed into a group, and when the group is full, the group reference is sent to Santa and no more can enter the waiting room or stable. Santa creates objects of work to represent the three tasks for either group to do and sends them to the groups to complete.

The source code for all three implementations is available in completion in Appendix A. This can be seen in both the depiction of the channels in Figure 5 as well as the source code

MAINTENANCE AT THE NORTH POLE


Figure 1. Java Process Overview.

25

Then the group is emptied, the individual members are released, and the waiting room or stable is released and set to empty. Finally Santa may return to sleep until the next group wakes him.

Figure 2. Santa's Friend State Flow

As mentioned above each of the elves and reindeer is of the class SantasFriend. The specific type is parameterized in the constructor for the class. The constructor also sets the individuals name and assigns a reference to the waiting room or stable. The SantasFriend class is a subclass of the NorthPoleConcurrentObject, which is a subclass of Thread and provides logging for the object. When the Thread is run the algorithm depicted in Figure 2 occurs. Each object tries to call the waiting room object to gain entry to the waiting room. If the object is allowed to enter the waiting room, then it calls its own method withSanta(). This method attempts to take from a SynchronousQueue, which will block until something is put into it. This

MAINTENANCE AT THE NORTH POLE

26

assures that the object will not do anything until it is done with Santa. When the group is finally released by Santa, the group object calls the doneWithSanta() method on each SantasFriend object, which puts something into the Queue, releasing the objected to loop through the algorithm again.

Figure 3. Waiting Room State Flow

The WaitingRoom, which is used for both the stable and waiting room objects in the main algorithm, is an object where the other objects are joined into groups of the correct size. The WaitingRoom object is executed in the main thread, so it does not block. It only receives requests from other concurrent objects such as Santa or SantasFriend objects. It has a simple

MAINTENANCE AT THE NORTH POLE

27

state mechanism, which is to be either full or not. It receives SantasFriend objects when it is not full, or rejects them when it is full. When the waiting room becomes full, it must continue to deal with concurrent requests from elves or reindeer, so it creates a MeetSanta object with the group of SantasFriend objects and submits this to an executor service to run in a separate thread. This thread continually tries to wake Santa until Santa can deal with the group. The group, when it is sent to Santa, is able to update the state of the waiting room when it is finished so that the waiting room will become not full.

Figure 4. Santa State Flow

MAINTENANCE AT THE NORTH POLE

28

The Santa Class is the most complex in the system. Since the activity of the SantasFriends objects is constricted by blocking when they are in the waiting room, Santa is responsible for initiating most of the activity within the simulation. Initially when run() is called on the Santa object, the object calls its sleep() method. This method simply sets the state of Santa to a sleeping state. The object does nothing until it is called from the waiting room or stable. When this happens the Santa object makes calls to the stable and the waiting room objects to check whether all of the reindeer are waiting, since the reindeer group has priority. After discovering which object is waiting, then it passes the group into either the deliverToys() method, or to the consultOnRD() method for the reindeer or elves, respectively. Each of these methods contains a sequence of actions to be performed. Before doing anything, a device for controlling concurrent action called a cyclic barrier is created. This is a barrier to further activity until a certain number of parties call await() on the cyclic barrier. This is set to wait for two calls, one for Santa to wait on, and one for the group to call when finished. Each Unit of Work is sent to a single threaded executor service. This allows the work to be done in a separate thread so that Santa can just wait until the work is finished, but since the executor service is in a single thread it guarantees that the work is done in the order submitted. The final unit of work for either group is Release Group, at this point the group will call await() on the cyclic barrier. This will release both the group and Santa. Santa will then release the group in the stable or waiting room as well. This sets the waiting room to empty so that it can accept more visitors. Finally the Santa object will call sleep() on itself again, which will put it in the correct state to repeat the above algorithm.

MAINTENANCE AT THE NORTH POLE JCSP

29

As opposed to the pure Java version, the version that uses the JCSP library does not make use of explicit calls to anything related to threads or any Java concurrency primitives such as the cyclic barrier. Rather than extending the Thread class, each JCSP class extends the CSProcess class. This means that it will be forced to implement the run() method, and that it will be able to run in a way that does not block the main thread of execution when executing the actions specified in its run method.

Figure 5. CSP Process and Channel Overview

Another primary difference is that there is not any explicit coupling between the classes. In the above description of the Java version, each class needed to have references to other classes to make calls to that objects methods in order to force that class to do some activity. In the JCSP library each process only has references to channels of communication. There is no assumption

MAINTENANCE AT THE NORTH POLE

30

made internally about what is at the other end of a channel when a JCSP process uses a channel to communicate. It could be a single process handling many channels or one process could be at the end of each channel. There are two basic operations that can happen over channels. Either a process can send to or read from a channel. When a process reads from a channel, it is blocked until it receives something from the channel. This means that another process needs to send something on that channel in order for a process to continue its algorithm. Figure 5 depicts the Santa Claus algorithm from the perspective of processes and channels. The channels are the darker, long boxes with a single open end. The processes are depicted through the square boxes. Another feature of JCSP used in this algorithm are the grouping mechanisms, depicted here by circles. These allow processes to join groups and wait until the group is terminated.

Figure 6. CSP Reindeer Process

MAINTENANCE AT THE NORTH POLE

31

In a JCSP program the organization of channels is the most complex aspect of design2. Each process is relatively simple in comparison. The following section will show how each process makes use of the channels of communication to synchronize its activity with other processes. Figure 6 shows the reindeer process. This process begins by waiting on the stable, which is a barrier. This means that the stable is a type of channel that is a grouping mechanism. All of the reindeer processes are connected to it, and when they all call the sync() method on this barrier, then it will release all of the processes at the same time. In this case, Santa also has a reference to this channel, and he must call it to release the reindeer. After this the reindeer process will write to the harness channel, read from the harnessed channel, and again synchronize on a barrier, this time the sleigh barrier. Finally the reindeer process reads from the returned and the unharnessed channels, which allow it to cycle through the algorithm again. The elf process, depicted in Figure 7, is very much similar to the reindeer process, however instead of synchronizing on a barrier, the elf process falls into a bucket. A bucket is different from a barrier in the sense that it can receive an unlimited number of processes and will only release when an outside processes flushes the bucket. In this case when the bucket is flushed, that means that the elf process is able to communicate on the consulting channels, which are supposed to be connected to Santa. Another main difference between the pure Java version and the JCSP version is that in the JCSP version only the elves need a waiting room. Since the reindeer can use JCSPs synchronization primitives to all wait for one another, they do not need a special waiting room.

This can be seen in both the depiction of the channels in Figure 5 as well as the source code available in Appendix A.

MAINTENANCE AT THE NORTH POLE

32

The elves do need a waiting room because there are more elves than will be meeting with Santa, and the waiting room guarantees that only three will be able to progress to that stage. The

Figure 7. CSP Elf Process

Figure 8. CSP Waiting Room Process

MAINTENANCE AT THE NORTH POLE

33

waiting room does not have a linear series of activities like the other processes have. Instead the waiting room makes extensive use of an alternate. This allows the processes to wait for several channels at once and select from the channel where a message is sent first. The waiting room process first waits for communication from the Santa process before sending the message for the elf processes to begin their algorithms. Similarly the consultation over channel may read from the need to consult channel, the consultation over channel, or it may arrive at a precondition to flush the elf bucket when the elf group size is equal to three. The waiting room process continually loops choosing one of the three alternatives. The Santa process is also relatively simpler than in the Java version. It simply chooses from between the elf or reindeer channels based on the reindeer priority. This is accomplished by using a JCSP priority select alternative, which will select whichever channel receives a message first unless both of them receive messages at the same time. After selecting a channel, the Santa process will communicate exclusively with channels from that group. In the case of an elf meeting, Santa will write three messages to the channels that are connected to the elves. In the case of the reindeer, Santa will write three messages, and then call the synchronize message on the sleigh barrier

MAINTENANCE AT THE NORTH POLE

34

Figure 9. CSP Santa Process

Akka In the actor version of this program, as opposed to the previous two versions, everything is implemented asynchronously. This means that no object or actor will ever block or wait for anything. The main challenge in implementing the Santa Claus problem in terms of actors is that it is primarily a problem of synchronization. If no actor will ever wait for anything, the main difficultly is to make sure that things happen in the algorithm in the correct order. Like the JCSP version, the Akka version uses message passing in order to communicate and accomplish all tasks. Unlike the JCSP version, the Akka version is not entirely free of coupling. Although an actor may not ever reference another actors internal methods, in the actor version messages are sent to other actors by reference or address. Since the actors are not communicating over predefined channels, they may sometimes need to hold onto another actors reference. It is more typical however, to simply respond to the last actor from whom a message

MAINTENANCE AT THE NORTH POLE

35

was received. Another primary difference is that the type of messages that an actor will be receiving is not made available publicly. Rather when a message is received usually it is processed by matching it through a series of if-then statements that will evaluate the contents of the message as a string. Because this is not necessarily a safe way to pass and receive messages, for this program particular message types were defined in a Java enum, simply entitled NorthPoleMsg. Then when a message is sent or received, it can be sorted using the same enum in a switch statement. Finally, a wrapper message was defined in order to allow sending the group type and a list of actor references along with the enumerated message type. This is primarily so that the Santa actor can order the group activities by sending messages to the whole list of actors and also so that Santa and the waiting room can define correct state and behavior based on the type of the group, elves or reindeer. In the Akka version of the Santa Claus problem each actor is a subclass of the NothPoleActor class. This class gives a logging method, a way to delay sending messages in order to simulate waiting, and a way to set its state. In addition to the basic actor model, each actor implements a finite state machine. This means that in addition to responding to messages, an actor can also choose which way to respond to messages based on its current state, which it may set according to messages received. So in order to understand an actor system, all that is necessary is to understand the messages that an actor can receive, the states that an actor can be in, and the actions that an actor can do or messages an actor can send in response.

MAINTENANCE AT THE NORTH POLE

36

Figure 10. Actor Version Overview with Connected Messages

MAINTENANCE AT THE NORTH POLE

37

In the diagrams of the actor classes presented (Figures 11-14) the messages that an actor can receive are represented by the arrow-like tab that is pointing inward. The states that an actor can take are represented by boxes in the center. Finally, the outgoing messages that an actor can send are represented by the outward pointing arrow-like tabs. The connections between the incoming messages, state, and outgoing messages are represented by connected lines. The elf and reindeer actors are extremely simple in that they only receive messages, set state, and send messages. However the waiting room and Santa actors are slightly more complex since they send messages based on their internal state. The waiting room actor contains both the groups of reindeer and elves. It receives wait messages from reindeer and elves. It has a state that represents the fullness of the waiting room for both the reindeer and elves. If the message received is for a group that is not full, then the actor is added to the group. If it is the last message before the group becomes full, the waiting room sends back the Last message, which signals that actor to send a message to Santa. Finally, Santa will also send a Dismiss message to the waiting room. Upon receiving this message the waiting room will clear the group and send a message to each actor that will enable them to return to the beginning of their messaging cycle. The Santa actor only receives two types of messages, the Wake Up and Done messages. When the Wake Up message is received, Santa first queues it to make sure that if both groups are waiting that the reindeer are serviced first. When Santa has decided which group to service he sets his state, either as Welcoming Reindeer or Welcoming Elves. The he initiates a communication with that group. After each message that Santa sends to a group, each member responds with Done. Santa holds a counter to make sure that all of the actors have responded, when they have, he changes his state to the next state and sends the next type of message to the group. Finally when the last done message is received, Santa changes his state to

MAINTENANCE AT THE NORTH POLE

38

Sleeping again. One final feature that Santa has is the ability to reject a group of actors when he is not in the sleeping state. If this is the case, he will send the Wait message, which will cause the sender to requeue the message.

Figure 11. Reindeer Actor Model

MAINTENANCE AT THE NORTH POLE

39

Figure 12. Elf Actor Model

Figure 13. Waiting Room Actor Model

MAINTENANCE AT THE NORTH POLE

40

Figure 14. Santa Actor Model

MAINTENANCE AT THE NORTH POLE Maintainability Issues Changeability

41

In order to test the maintainability of each paradigm from an experiential perspective and to evaluate the metrics results obtained on the initial solutions, four additional iterations of maintenance on each version was conducted. Although this experiment cannot replace the study of software in industry, it can lend a different perspective because each version exhibits the same behavior and so can be directly compared. Iteration 2. Visualized websocket server The goal of the second iteration was to attach a server that pushes messages over websockets to connected clients. This will send an updated message every time a member of the software simulation logs its status. The message is then appended to the character picture using client side JavaScript. The client is implemented exactly the same for each version, so the primary challenge is integrating previous logging functions into the new websocket environment using the technology available for each paradigm.

Figure 15. Screenshot of Final Version

MAINTENANCE AT THE NORTH POLE

42

The server technology is implemented using a framework called Atmosphere (http://asyncio.org). This allows for a websocket server to be embedded in an application. The primary way of pushing messages to clients is through the built in Broadcast class. This was the area that needed to be implemented differently according to each paradigm. This can be considered a test of each paradigms way of handling outward facing dependencies. The pure Java version was created by implementing a class, BroadcastOutMain that is a plain Java class with a single method, send(). This method is then instantiated in the base class for each class in the simulation, the NorthPoleConcurrentObject. In addition to calling the basic system out, the object that is logging a message also calls the send message. In the JCSP version, the BroadcastOutMain class is implemented as a process. This process has a single channel, an input connection. The process continually reads from the channel and sends the message out to the connected clients. A connection to the output of this channel was implemented in the base class for each NorthPoleProcess class, but because each class has individual connections to the channel, the channel needed to be added to each class constructor and passed into the super class constructor. In the Actor version, the BroadcastOutMain class is implemented as an actor. This class waits to asynchronously process messages and to push them to connected clients. Because Actors can be started without much overhead, the BroadcastOutMain was added as a field to the base NorthPoleActor class. Each time an actor logs a message, it also sends a message with the contents to the BroadcastOutMain actor. Iteration 3. Add Mrs. Claus The addition of Mrs. Claus to the program is a somewhat more thorough test of each paradigms capability to be modified. The rules for implementing Mrs. Claus in the algorithm

MAINTENANCE AT THE NORTH POLE

43

are: Mrs. Claus will come to Santa with cookies. Santa can only receive the cookies from Mrs. Claus when he is with the Elves. When Santa is done with the cookies, Mrs. Claus will return home, and then after resting try to bring more cookies. If Santa is sleeping or delivering presents, Mrs. Claus will wait until Santa is with the elves. In the pure Java implementation, Mrs. Claus cannot call any of Santas methods directly because she may interrupt Santas thread of execution. Instead in the Java version, a SnackRoom class also needed to be implemented. Mrs. Claus calls the SnackRoom waitWithCookies() method. This method attempts to pull from a blocking queue that is empty. So this causes Mrs. Claus to block until the queue is filled. Since Santa cannot be called asynchronously, he needs to check whether Mrs. Claus is waiting in between every activity while meeting with a group of elves. Once he has found Mrs. Claus in the snack room and eaten cookies, he can call the snack rooms doneEating() method. This puts something into the queue that is blocking Mrs. Claus, releasing her to repeat the cycle. In the JCSP version, the only class that needs to be added is Mrs. Claus. Rather than writing a new class for a synchronization location, this version makes use of a built in JCSP synchronization utility. The Bucket utility is used in order for Mrs. Claus to block while she waits for Santa. While Santa is meeting with the Elves though, he needs to check whether the Bucket is full. If he finds Mrs. Claus waiting in the Bucket, he eats cookies and then releases her from the Bucket to continue her cycle. In the Actor version, Mrs. Claus can send messages to Santa asynchronously, and even if Santa is sleeping or gone with the reindeer, he can send a reply to Mrs. Claus to let her know what his state is. If she receives a wait message, she requeues a message to be sent to Santa two seconds later. If he receives this message while he is with the Elves, then he can change his state to Eating Cookies and when elves send him a Done message, he can tell them to wait. Then

MAINTENANCE AT THE NORTH POLE

44

the elves will resend messages until Santa is done eating cookies. This required changes to the Santa as well as the elves classes. Iteration 4. Add user interaction The use of websockets for the server and client technology allows for bi-directional communication, so a user can sign in to the application. When the user signs in to the application the first request does not alter the state of the server, but with each addition message that the user sends the application stores the messages as wishes. When Santa is with the reindeer, and the reindeer deliver the toys, then the wish list send a list of all of the gifts to the client. The challenge in this is to create an object that can interface with the input from the websocket server, maintain its state, and then transfer its state back to the interface. This is primarily a problem of coupling, because information is coming from multiple directions. It also is important that the wish list is not corrupted by access from several threads.

Figure 16. High Level Overview of User Interaction

MAINTENANCE AT THE NORTH POLE

45

The Java version of the wish list is implemented as a class with two static methods. The methods need to be static because in order for the Class that receives websocket requests to communicate with the rest of the application, the dependency must be injected. Because the framework hides the instantiation of this class, the dependency cannot be supplied with a constructor. It needs to be supplied at runtime. So the static methods of the wish list class are called from both the server and from the Santa Claus object. The wish list class also has a BroadcastOutMain instance available to send the delivery list to the interface. In the JCSP version, the wish list class is implemented as a CSP process. Rather than injecting the class as a dependency to receive messages from the server, a channel endpoint is supplied to the server component. The wish list also has wish list input, wish list output, and delivery message input channels. The algorithm for this process is implemented by selecting an alternate. Depending on whether the input message is received from the wish list or the delivery channels, either the process will add to the wish list or it will send a delivery message to the broadcast object. In this implementation there are no direct dependencies on the wish list, and the wish list does not have a direct dependency on a particular implementation of the broadcast output. The Akka implementation of the wish list is somewhat of a compromise between the two above approaches in terms of dependencies. The wish list is implemented as an actor that has not state and receives only two types of messages. If the message is a Deliver message, then the wish list sends the list to the broadcast actor. All other messages are appended to the wish list. In order to inject the wish list, the server has a static variable that is at runtime assigned the reference to the wish list actor. The Santa object also has a reference to the actor address passed into its constructor when it is created. Although they both have a reference to the wish list actor, it is not the same as a fully coupled relationship. The actor reference could be dynamically

MAINTENANCE AT THE NORTH POLE

46

reassigned, and since no methods of the actor are directly called, any wish list implementation could be exchanged. Programming to an actor model is similar in this way to programming to interfaces. Iteration 5. Distribute with ZeroMQ The final change was to make certain components of the program able to be run in separate processes, and hence distributable. For this task the first decision that needed to be made was to decide whether or not the individual frameworks distributed programming features would be used. The problem with using the built in features was two-fold. First of all, Java does not have any native support for distributed programming, so this would put the Java version at an unfair disadvantage. This would amount to testing framework features rather than testing the programming design method available in a given paradigm, which is the aim of this thesis. Secondly, in this case using the built in distributed functionality of both Akka and JCSP is more complicated than using an additional messaging library. The messaging library used in this thesis is ZeroMQ (http://zeromq.org/). The benefit of using the ZeroMQ library is that it does not hide the inherent complexity of distributed programming, but it does provide a unified and simple interface for a number of very useful distributed communication patterns. This thesis exclusively made use of ZeroMQs Push-Pull pattern because multiple agents can push to the message queue on the same port. The pattern for distributing the application was to divide the basic North Pole simulation, including Mrs. Claus from the server and from the wish list. So there are three basic components to the distributed version, the NorthPole, the Server, and the WishList. For the pure Java version two utility classes were implemented, the InputService and the OutputService. The input service always runs in its own thread, and it implements the Runnable

MAINTENANCE AT THE NORTH POLE

47

interface. The input service also needs to implement the command design pattern. In this pattern, the behavior or action that is accomplished upon receiving an input message from the queue is dynamically assigned at runtime. This action is always programmed to the interface Command. The Command interface has the method execute() which is always the method that must be executed when a message is received. In order to distributed the server and the wish list, both the BroadcastOutMain and WishList classes were modified to implement the Command interface. Then at runtime these objects are passed into the InputService objects that will receive distributed communications for them. The OutputService is relatively simpler. It contains one method, send(), that is executed by any object that holds a reference to the output object. When this method is called, it pushes the message to the message queue. The JCSP version also implements an input and output service, but they are implemented as processes rather than pure Java classes. The input service receives a message from the message queue, and can pass it on to any other process using a shared channel. This means that there is no need to create a design pattern to trigger an action remotely. Similarly, the output service contains a ZeroMQ connection point and a CSP channel connection endpoint. Any process can connect to the output service by connection to the other end of the channel. When distributing the processes in the JCSP version, it was only necessary to instantiate an output or input service in the place of any CSP process that would be run remotely and then connect these service to the previously existing channels. In creating the Akka version there was one significant design consideration whether there should be a single actor created in each module to handle connections to ZeroMQ or whether each actor should have a subservient actor to handle connections. The decision to give each actor a subservient actor to handle these connections was made in order to reduce the complexity that would be involved with passing references to the output service into the

MAINTENANCE AT THE NORTH POLE

48

constructors of each actor instance and passing the references to actors to the input service. The output service is instantiated in the base class of the actors, and it serves as a replacement for whatever output an actor would have previously needed to have. In the case of the ZeroMQ input service, a subservient actor is created with a reference to its supervisor actor. When the input service receives an input from the message queue, then it sends a message to its supervisor with the contents. In a sense, distributing the Akka application actually simplified its design because it eliminated some explicit dependencies between actors. Now the distributed messages can be routed using ZeroMQs features rather than by managing actor references. Gathering Data The code for each iteration was managed in Git repositories. Each version was assigned to a separate Git repository. The code was arranged into separate commits for each iteration. This allows for the particular code changes made to be investigated by examining the differences between commits. The tool SourceTree (http://www.sourcetreeapp.com/) was used to examine these changes and to manage the repositories. Data was gathered using two freely available code analysis tool kits. The most robust and useful kit was SonarQube (http://www.sonarqube.org/). This tool kit is commonly used in development organizations to monitor the quality and growth of their codebase. In the context of this research, it was used to gather several key metrics. Specifically, Sonar was used to gather data on the lines of code, aggregate McCabe complexity, and Chidamber and Kemerers coupling metrics both efferent and afferent coupling. Since this tool was employed after the development, each iteration commit was revisited and rebuilt using Maven

(http://maven.apache.org/) and then the data was gathered using the Sonar Maven plugin. After this the metrics were calculated for each version, they were copied to a csv (comma separated

MAINTENANCE AT THE NORTH POLE

49

values) file for later analysis and for building the graphs used in the results section. The second tool that was used was Code Pro AnalytiX (https://developers.google.com/java-devtools/codepro/doc/analytix). This was primarily used to calculate Halsead metrics for the projects. Again, each iteration in each version of the project was analyzed. The results were saved with the previous results from Sonar. Finally, in order to gain more insight into the change in metrics between versions, the growth was also calculated for each iteration. The growth was calculated relative to the starting metric for each version and saved in a separate csv file for comparison.

MAINTENANCE AT THE NORTH POLE Chapter 4. Results and Analysis

50

In addition to examining the types of changes that occur during the course of developing the applications, the goal of this thesis is to examine how apt the currently available software metrics are at 1) predicting the maintainability of the application over time 2) describing problems in the areas of analyzability and testability, which are the key components of maintainability. This chapter presents the results obtained from gathering and aggregating some key metrics for each of the projects. Each metric is presented both in terms of the actual numbers that were generated and in terms of the growth of the metric over the five iterations of each version. Metrics for Maintainability Lines of Code
MEE! UEE! KEE! DEE! <EE! :EE! ?EE! 5EE! E! 5! ?! :! <! D!
Figure 17. Comparison of Lines of Code over Five Iterations

"#*%2!)C!6)0%!;+$)&!P%&2#)*! "#*%2!)C!6)0%!-'.'!P%&2#)*! "#*%2!)C!6)0%!678!P%&2#)*!

MAINTENANCE AT THE NORTH POLE

51

54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 18. Comparison of Growth in Lines of Code over Five Iterations

"#*%2!)C!6)0%!;+$)&!P%&2#)*! "#*%2!)C!6)0%!-'.'!P%&2#)*! "#*%2!)C!6)0%!678!P%&2#)*!

Although the lines of code metric is the least descriptive of the metrics, it prefigures the results that are seen in the rest of the metrics. The Akka version had the most lines of code in the first iteration, and continued to have the most lines of code through each version. This is primarily because at the outset the Akka version needed some extra code added for two features that were implicit in the other versions. The first of these is the feature to guarantee the type of messages. The second is the feature to be able to maintain synchronization through the use of explicit state control. However examining the growth in lines of code, both the JCSP and the pure Java versions had a sustained higher rate of growth. This is because with the initial infrastructure in place, in general the Akka version required less code to implement new features. In extending the Java version, there were many times that more verbose design patterns needed to be implemented to achieve the same extensibility that was available through message passing. One example of this in particular was the need to implement the command interface in order to trigger events in the distributed version. The largest cause of growth in the JCSP version, apart from the addition of features, was the need to add channels for each process. This requires some verbosity because each channel must be created in the main class, then it must also be added as a field to

MAINTENANCE AT THE NORTH POLE

52

both the sending and receiving objects, and also must be assigned in the constructor in both the sending and receiving objects. Lines of Code Per Method The lines of code per method metric is significant in that it is the only metric where the Akka version was not the highest throughout. In the case of the lines of code per method, each version had an overall decrease in the metric over the course of five iterations. The reason for this is that in each version, in general the largest average method is the primary thread of execution in the Santa Claus class. So with each iteration this is balanced by the addition of shorter methods. However some additions, such as the addition of Mrs. Claus in the third iteration, cause the main Santa Claus to increase in size, increasing the size of the average.
?E! 5D! 5E! D! E! 5! ?! :! <! D!
Figure 19. Comparison of Lines of Code per Method over Five Iterations

"#*%2!)C!6)0%!8%&!F%$>)0! ;+$)&!P%&2#)*! "#*%2!)C!6)0%!8%&!F%$>)0! -'.'!P%&2#)*! "#*%2!)C!6)0%!8%&!F%$>)0!678! P%&2#)*!

E! XE4ED! XE45! XE45D! XE4?! XE4?D! XE4:! XE4:D! XE4<!


Figure 20. Comparison of Growth in Lines of Code per Method over Five Iterations

5!

?!

:!

<!

D! "#*%2!)C!6)0%!8%&!F%$>)0! ;+$)&!P%&2#)*! "#*%2!)C!6)0%!8%&!F%$>)0! -'.'!P%&2#)*! "#*%2!)C!6)0%!8%&!F%$>)0!678! P%&2#)*!

MAINTENANCE AT THE NORTH POLE

53

The distribution in the results for this method can be explained by the nature of the paradigms implementations. The JCSP has the highest average method size because the entire functionality is dealt with in a single method, run(), for each process. The pure Java version however relied on making many small methods publicly available so that concurrent objects could synchronize with one another. The Akka version is somewhere in the middle. Each actor has a large method to handle the logic in receiving messages. However, the actor may use separate internal methods to deal with more complex message responses. Cyclomatic Complexity (Average)
:! ?4D! ?! 54D! 5! E4D! E! 5! ?! :! <! D! 6,+/)9'$#+!6)93/%G#$,! ;+$)&!P%&2#)*! 6,+/)9'$#+!6)93/%G#$,!-'.'! P%&2#)*! 6,+/)9'$#+!6)93/%G#$,!678! P%&2#)*!

Figure 21. Comparison of Average Cyclomatic Complexity over Five Iterations

E! XE4ED! XE45! XE45D! XE4?! XE4?D! XE4:!


Figure 22. Comparison of Growth in Average Cyclomatic Complexity over Five Iterations

5!

?!

:!

<!

D!

6,+/)9'$#+!6)93/%G#$,! ;+$)&!P%&2#)*! 6,+/)9'$#+!6)93/%G#$,!-'.'! P%&2#)*! 6,+/)9'$#+!6)93/%G#$,!678! P%&2#)*!

The cyclomatic complexity metric measures code complexity by evaluating the possible branches in logic in the code. Similar to the lines of code per method, the average cyclomatic complexity is an average over all of the classes in a given version. Another similarity is that with each iteration, almost every version decreased in average complexity. Again the culprit for the

MAINTENANCE AT THE NORTH POLE

54

initial complexity is the Santa Claus class, which contains branching logic, in particular for dealing with the different groups of visitors in the Java and JCSP versions, and for processing a variety of different messages in the Akka version. One point of interest for this metric is that it shows a difference in implementing the Mrs. Claus iteration. In both the Java and JCSP versions there was a growth in the relative average complexity from the previous iteration, while the Akka version continued to decline in average complexity. This is because the Akka version did not require much additional logical branching to add concurrent interaction. However, because the JCSP and Java versions did not support asynchronous communication directly from Mrs. Claus to Santa they required additional logical branching during the Santa-elf rendezvous. Complexity (Aggregate Sum)
5<E! 5?E! 5EE! ME! KE! <E! ?E! E! 5! ?! :! <! D!

6)93/%G#$,!;+$)&!P%&2#)*! 6)93/%G#$,!-'.'!P%&2#)*! 6)93/%G#$,!678!P%&2#)*!

Figure 23. Comparison of Complexity over Five Iterations

54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 24. Comparison of Growth in Complexity over Five Iterations

6)93/%G#$,!;+$)&!P%&2#)*! 6)93/%G#$,!-'.'!P%&2#)*! 6)93/%G#$,!678!P%&2#)*!

The aggregate sum in complexity is a measure of cyclomatic complexity, but rather than being averaged over classes, the complexity for each class is added to the whole. For this reason,

MAINTENANCE AT THE NORTH POLE

55

each additional branch in logic adds to the number. The interesting aspect of this metric is that for the most part all of the versions grow roughly in parallel. The initial complexity of the Akka version puts it at a much higher level of complexity than the other versions, it does not converge with the other versions in the same way that it does for some of the other metrics. This is because with each additional feature, another message must be added to some actors onRecieve() method, which means at least one additional branch in logic. The only slight variance is with the addition of the Mrs. Claus feature, as described in the section above. Afferent Coupling Afferent coupling refers to the number of classes that reference a particular class. For example, in the application there is a Data class that is shared as the common way of transporting

KE! DE! <E! :E! ?E! 5E! E! 5! ?! :! <! D!


Figure 25. Comparison of Afferent Coupling over Five Iterations

;CC%&%*$!6)(3/#*1!;+$)&! P%&2#)*! ;CC%&%*$!6)(3/#*1!-'.'! P%&2#)*! ;CC%&%*$!6)(3/#*1!678! P%&2#)*!

D! <! :! ?! 5! E! 5! ?! :! <! D!
Figure 26. Comparison of Growth in Afferent Coupling over Five Iterations

;CC%&%*$!6)(3/#*1!678! P%&2#)*! ;CC%&%*$!6)(3/#*1!-'.'! P%&2#)*! ;CC%&%*$!6)(3/#*1!;+$)&! P%&2#)*!

MAINTENANCE AT THE NORTH POLE

56

information between the client and the server and between the server and the other classes in the simulation or the wish list class. If this class is used by eight classes, then the afferent coupling will increase by eight for that class. In fact this is exactly the case for the second iteration in which the Data class was added. All of the versions saw the same amount of increase in afferent coupling because they all make use of this utility class in the same way. The afferent coupling shows an interesting pattern that divides the two types of message passing concurrency from the pure Java version that relies on direct method calls for communication between classes. While the two message passing classes grow in a near parallel, the pure Java version grows at a much steeper rate. So much so that by the fifth iteration, the pure Java version has almost outstripped the Akka version. The Akka version shows almost no growth in coupling over the iterations. This is because there is no coupling between the actors, the only cause of initial coupling, and the cause of any increase in coupling, is that the actor model requires a shared data model for the messages to achieve a sort of type safety. The JCSP version also does not have direct coupling between processes, but coupling occurs by sharing channels that are properly fields of the main class. Efferent Coupling The efferent coupling metric is a mirror of the afferent coupling. It refers to the number of outside objects that a particular class references. The pattern is exactly the same as the afferent coupling results, and the interpretation of the metric should also be the same.

MAINTENANCE AT THE NORTH POLE


KE! DE! <E! :E! ?E! 5E! E! 5! ?! :! <! D!
Figure 27. Comparison of Efferent Coupling over Five Iterations

57

JCC%&%*$!6)(3/#*1!;+$)&! P%&2#)*! JCC%&%*$!6)(3/#*1!-'.'! P%&2#)*! JCC%&%*$!6)(3/#*1!678! P%&2#)*!

?4D! ?! 54D! 5! E4D! E! 5! ?! :! <! D!


Figure 28. Comparison of Growth in Efferent Coupling over Five Iterations

JCC%&%*$!6)(3/#*1!;+$)&! P%&2#)*! JCC%&%*$!6)(3/#*1!-'.'! P%&2#)*! JCC%&%*$!6)(3/#*1!678! P%&2#)*!

Halstead Metrics The Halstead metrics are grouped together in this section. As mentioned in the literature review, Halstead metrics build upon the permutations of interpreting the relationship between operands and operators. The definition of the two can be ambiguous, particularly in either functional or purely object oriented languages. However in Java, there are definite operands, which are terms such as class names, method names, variable names, or parameters. Operators are generally part of the syntax, such as addition, subtraction, or assignment operators. The primary idea in Halsteads metrics is that as the operands and operators increase, particularly unique operands and operators measured against and ideal number, the program becomes much more difficult to understand and maintain.

MAINTENANCE AT THE NORTH POLE Operands


?EEE! 5DEE! L3%&'*02!;+$)&!P%&2#)*! 5EEE! DEE! E! 5! ?! :! <! D!
Figure 29. Comparison of Operands over Five Iterations

58

L3%&'*02!-'.'!P%&2#)*! L3%&'*02!678!P%&2#)*!

54<! 54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 30. Comparison of Growth in Operands over Five Iterations

L3%&'*02!;+$)&!P%&2#)*! L3%&'*02!-'.'!P%&2#)*! L3%&'*02!678!P%&2#)*!

The operands metrics is a sum of the complete number of operands used in a program. This could be considered to be the real size of a program. Lines of code is less specific because any number of operands could be written on the same line. The interesting aspect of this metric is that each version grew largely in parallel over the course of five iterations. If viewed according to the operands metric, there would not be any particular advantage to using any of the concurrency paradigms. Operators The measure of operators is the sum of all operators used in the program. This metric is unique for this project in that it is the only metric in which both the Akka and JCSP versions are nearly identical over five versions. This means that although the Akka version used many more operands and had more lines of code, it used the relatively less operators. This makes sense in

MAINTENANCE AT THE NORTH POLE

59

terms of the how the paradigm works. In general the Akka version does not make use of operators as much, rather it matches messages and sends responses using primarily operands and logical branching.

UEE! KEE! DEE! <EE! :EE! ?EE! 5EE! E! 5! ?! :! <! D!


Figure 31. Comparison of Operators over Five Iterations

L3%&'$)&2!;+$)&!P%&2#)*! L3%&'$)&2!-'.'!P%&2#)*! L3%&'$)&2!678!P%&2#)*!

54K! 54<! 54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 32. Comparison of Growth in Operators over Five Iterations

L3%&'$)&2!;+$)&!P%&2#)*! L3%&'$)&2!-'.'!P%&2#)*! L3%&'$)&2!678!P%&2#)*!

Unique Operands The unique operands metric is exactly as the title describes. Each type of operand is counted exactly once. The value in calculating this metric will be seen later, but in general it can be useful in comparison to the operands. If a program has a high ratio of unique operands to total operands, then it may mean that the program is not properly abstracted and the program may be more difficult to understand. The calculation of this metric for this project in particular

MAINTENANCE AT THE NORTH POLE


:DE! :EE! ?DE! ?EE! 5DE! 5EE! DE! E! 5! ?! :! <! D!
Figure 33. Comparison of Unique Operands over Five Iterations

60

N*#O(%!L3%&'*02!;+$)&! P%&2#)*! N*#O(%!L3%&'*02!-'.'! P%&2#)*! N*#O(%!L3%&'*02!678! P%&2#)*!

54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 34. Comparison of Growth in Unique Operands over Five Iterations

N*#O(%!L3%&'*02!;+$)&! P%&2#)*! N*#O(%!L3%&'*02!-'.'! P%&2#)*! N*#O(%!L3%&'*02!678! P%&2#)*!

Unique Operators The unique operators metric is the sum of each operator in the program counted exactly once. Because the number of unique operators available and used in a program is typically defined by the language this number has very little to do with the actual coding style. Rather, it is used in other metrics as a kind of basis for comparison and as a part the compound metrics such as program vocabulary. As expected there is very little real difference in the numbers for this metric between the versions, and because the number is quite small, this metric appears to have more volatility than the other metrics.

MAINTENANCE AT THE NORTH POLE


:E! ?D! ?E! 5D! 5E! D! E! 5! ?! :! <! D!
Figure 35. Comparison of Unique Operators over Five Iterations

61

N*#O(%!L3%&'$)&2!;+$)&! P%&2#)*! N*#O(%!L3%&'$)&2!-'.'! P%&2#)*! N*#O(%!L3%&'$)&2!678! P%&2#)*!

E4<! E4:! E4?! E45! E! 5! ?! :! <! D!


Figure 36. Comparison of Growth in Unique Operators over Five Iterations

N*#O(%!L3%&'$)&2!;+$)&! P%&2#)*! N*#O(%!L3%&'$)&2!-'.'! P%&2#)*! N*#O(%!L3%&'$)&2!678! P%&2#)*!

Length The program length is defined as the combined total operands and operators for a program. This is really a much more accurate assessment of a program's length than lines of code because it is an assessment of what a program contains in total. Interestingly, while there was more divergence on the lines of code, the pattern for length over the course of five iterators for all three versions is that the actor version is about twice the length of the pure Java version. The JCSP version is just under twice the length of the pure Java version for most of the iterations. This indicates that there may be a possibility that either the use of external libraries may have an influence on general program verbosity or that the programming paradigms themselves are more verbose.

MAINTENANCE AT THE NORTH POLE


?DEE! ?EEE! 5DEE! 5EEE! DEE! E! 5! ?! :! <! D!
Figure 37. Comparison of Length over Five Iterations

62

"%*1$>!;+$)&!P%&2#)*! "%*1$>!-'.'!P%&2#)*! "%*1$>!678!P%&2#)*!

54<! 54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 38. Comparison of Growth in Length over Five Iterations

"%*1$>!;+$)&!P%&2#)*! "%*1$>!-'.'!P%&2#)*! "%*1$>!678!P%&2#)*!

Vocabulary The program vocabulary is the sum of the unique operands and the unique operators metrics for the program. This metrics shows a general convergence for the different versions over five iterations. By the fourth iteration, the JCSP and the pure Java version measure at exactly the same level. The Akka version also continues to increase at a lower percentage than the other versions so that by the end all three versions are approaching each other. This indicates the same thing that the convergence in unique operands does. The programs appear to be operating with the same vocabulary for solving the same problem. The differences that are maintained in the total length indicate that the same vocabulary is repeated more in the longer programs.

MAINTENANCE AT THE NORTH POLE


<EE! :EE! P)+'B(/'&,!;+$)&!P%&2#)*! ?EE! 5EE! E! 5! ?! :! <! D!
Figure 39. Comparison of Vocabulary over Five Iterations

63

P)+'B(/'&,!-'.'!P%&2#)*! P)+'B(/'&,!678!P%&2#)*!

54?! 5! E4M! E4K! E4<! E4?! E! 5! ?! :! <! D!


Figure 40. Comparison of Growth in Vocabulary over Five Iterations

P)+'B(/'&,!;+$)&!P%&2#)*! P)+'B(/'&,!-'.'!P%&2#)*! P)+'B(/'&,!678!P%&2#)*!

Volume The volume metric is an interpretation of the preceding metrics in terms of information theory. It makes used of the binary logarithm to indicate "the number of mental comparisons" that would be necessary for interpreting or writing a program (Menzies, Di Stefano, Chapman, & McGill, 2002, p. 3). The equation for deriving this metrics is Volume = Length + log2(Vocabulary). This metrics shows that the Java version requires significantly less "mental comparisons" than the Akka and JCSP versions. It also shows that each program grows at roughly the same percentage over the course of five iterations.

MAINTENANCE AT THE NORTH POLE


?DEEE! ?EEEE! 5DEEE! 5EEEE! DEEE! E! 5! ?! :! <! D!
Figure 41. Comparison of Volume over Five Iterations

64

P)/(9%!;+$)&!P%&2#)*! P)/(9%!-'.'!P%&2#)*! P)/(9%!678!P%&2#)*!

?! 54D! P)/(9%!;+$)&!P%&2#)*! 5! E4D! E! 5! ?! :! <! D!


Figure 42. Comparison of Growth in Volume over Five Iterations

P)/(9%!-'.'!P%&2#)*! P)/(9%!678!P%&2#)*!

MAINTENANCE AT THE NORTH POLE Chapter 5. General Analysis and Conclusions

65

The following section consists of the general analysis and conclusions drawn from the evidence in both the design aspects considered in the methodology section and the metrics considered in the results section. The design aspects provide a more semantic view of the program in terms of what can be understood by examining the design documents. The metric view measures more syntactical features of the programs. In some cases the metrics can be verified by comparison with the evidence from the design and implementation of the programs. In other cases, the metrics may reveal an aggregate view of the program that is not apparent from simply viewing the design. In other cases the metrics seem to contradict the view of the programs that is presented in the design documents. Analysis of paradigms General Analysis In the aggregate a pattern is visible in the metrics derived for the three versions of the Santa Claus program over the course of its evolution. The Akka version is typically the highest metric and remains so throughout each iteration. The Java version is typically the lowest metric and remains so throughout each iteration. The JCSP version is more variable, and sometimes trends closer to the Akka version, and at other times it is close to the Java version. When looking at growth however, the Akka version typically grows at the slowest rate and the Java version typically grows at the fastest rate. There are certain metrics, for example the Halstead metrics, in which the three versions grow in parallel. In other metrics, particularly complexity and coupling, the versions do not grow at a parallel rate, and it could be predicted that with enough iterations that the Java version would become the highest member in these metrics. If viewed solely from the perspective of the metric aggregates, it could be asserted that there is no benefit to using

MAINTENANCE AT THE NORTH POLE

66

either the CSP approach or the actor model over the pure Java approach in terms of code level maintainability. However, in analyzing the metrics in terms of how they relate to the semantics of the programs, some general tradeoffs can be seen that might motivate a decision to use one or the other in a software project. These can be categorized in terms of sets of binary decisions: design versus library enforced concurrency abstractions, atomic versus distributed algorithms, and coupling versus logical complexity. Design and Library Based Abstraction of Concurrent Elements The primary difference between the native Java version and the other two versions is that in order to create a workable solution, in some cases the program required more decisions in terms of design. For example, there are many more options in pure Java for distributing a message received from a message queue to the other threads of execution running in the program. In this case the decision was made to use a fairly simple pattern to pass the thread of execution to be updated into the constructor for the message queue class, creating a one-to-one relationship. If a more robust and "future proof" solution was needed, a different design such as the observer pattern could have been employed, resulting in an increased design complexity. On the other hand, the JCSP and Akka versions have one way to solve this problem, and it is built into the concurrency paradigm and tool set as message passing. However the Java program also is able to make use of some high-level concurrency constructs that are built into the language. The two that were most significant in reducing complexity and ensuring correctness in the Java version were: the use of blocking queues and cyclic barriers to regulate the synchronization between concurrent objects. However, because permitting access to object fields is generally considered poor object oriented design and could be potentially dangerous in concurrent access patterns, a level of abstraction may need to be built

MAINTENANCE AT THE NORTH POLE

67

around these concurrency primitives. One example of this is the use of the Snack Room abstraction to allow for synchronization between Santa and Mrs. Claus. In addition since the synchronization patterns are different for each class, it would be difficult to implement a reusable component just for this feature without actually needing to implement something similar to JCSPs channels. The general principle that can be drawn from this is the notion that over the long run, an important maintainability feature may be the use of unified abstractions for accomplishing similar work. This can be seen at work in the design artifacts for each version presented in the methodology section. The JCSP version of these diagrams presents a strongly unified abstraction that is a characteristic of both the library and the paradigm itself. All synchronization occurs over channels or a similar communication primitive, such as buckets or barriers. All processes are also implemented as a similar looping construct, with the main variation being whether branching is introduced via the CSP alternative construct. This is a unified model that can be summarized and communicated easily in design documents. In addition, the design diagrams show a high level of correspondence with the actual code implementation. The Akka version provides some level of a unified abstraction. The primary abstraction is that messages are the only type of event in this program. The actions of every object at every time depend on what type of message it is receiving. Therefore, each object has a single, long onRecieve() method. There are other abstractions that needed to be designed and maintained for the purposes of this program. Two examples are the abstraction for the message and the abstraction of actor state. In both the pure Java and the JCSP version, the problem of synchronization is solved by assuming that the state of any object is the same as the current method that it is blocked by. Since the actor model is non-blocking, this assumption cannot be used, so a state abstraction needs to be invented.

MAINTENANCE AT THE NORTH POLE

68

The application of this observation to maintainability is that for each necessary abstraction that is not maintained by the programming language, paradigm, or framework, one must be created and maintained by the development team. Another consequence of a lack of abstractions suitable to the problem is that a unified abstraction may never be found. If this is the case, for each feature addition a new way of solving a similar problem will need to be found. This can be seen by comparing the Akka and pure Java versions. In the Akka version the abstractions for state and messages were relatively simple and were able to be incorporated into the base class for all actors an equally applied throughout the application. So each subsequent addition was able to use the same abstraction. In the pure Java version however, a unified synchronization abstraction needed to be created, and so the Mrs. Claus and wish list feature additions use different synchronization abstractions, for example. This can also be seen to some degree by looking at the growth comparison for the coupling metrics and Halsteads vocabulary metric. These two metrics show that for each iteration more new abstractions were added to the pure Java version than to the Akka version. Looking at the metrics as a whole though shows that the Akka version had significant initial size, complexity, and coupling factors that persisted. The JCSP version, however, had a relatively low metric in all areas in comparison to the Akka version and relatively low growth in each metric in comparison to the Java version. Atomic and Distributed Algorithms In Akka, because there is not an individual algorithm that each actor follows, the algorithm itself is distributed. In other words the algorithm is only able to move forward by orchestrating the coordination of all the parts at once. CSP processes on the other hand, allow the algorithm to be separated into individual processes. Of course all of the processes need to be

MAINTENANCE AT THE NORTH POLE

69

working in order for the algorithm as a whole to move forward, but it is different in the sense that each smaller process has a formula for the order in which events occur. In terms of maintainability, either paradigm has benefits and drawbacks. The unordered nature of receiving messages in the actor model means that it is more flexible. This can be seen best in the example of the addition of the Mrs. Claus feature to the algorithm. In the actor paradigm, Santa could receive messages from Mrs. Claus at anytime, and when its state allowed it to processes those messages, the actor would, but the Java and JCSP models required that Santa explicitly check to see if Mrs. Claus was waiting between each step in the elf-processing algorithm. The main benefit of having an atomic approach to an objects algorithm is that by looking at the design diagrams and the code, an order of operations for the whole program can be easily inferred. In terms of the commonly available metrics, there does not seem to be one that would adequately express this concept. Complexity and Coupling An analysis of the source code and metrics reveals a pattern of trading complexity for coupling in the concurrency paradigms. The message passing programs are highly decoupled, but incur much higher complexity because they have a branch in logic where a direct method invocation would have simply led to a higher degree of coupling. The question that should be answered, though, is whether there is a clear maintainability benefit to trading complexity for coupling or coupling for complexity. One way to answer this question is to examine the changes necessary to implement a feature. A comparison of the git logs for each version for the fifth iteration shows that the pure Java version required 13 files to be changed, 195 lines of code to be added, and 22 lines of code

MAINTENANCE AT THE NORTH POLE

70

to be removed, the JCSP version required 8 files to be changed, 163 lines of code to be added, and 8 lines of code to be removed, and the Akka version required 10 files to be changed, 170 lines of code to be added, and 13 lines of code to be deleted. It seems clear that in terms of the changes necessary that as the Java version increased in coupling it required more files to be changed and more code to be changed. This project is relatively small, but as the size of the code base increased, it is likely that the differences would be magnified. This point of view could be countered with a compelling objection. Even though there may be somewhat more changes required in the more highly coupled version, this does not correlate to a convergence or divergence in the actual growth of more specific size metrics, such as the Halstead volume. In the end however, the actual changes to the code base are equivalent to real work, whereas the Halstead metric is an approximation of work that does not take the software evolution history into account. Analysis of maintainability indicators In the above analysis certain maintainability indicators proved to be useful in terms of the general concept of maintainability. The two key maintainability factors that are able to be identified through metrics are analyzability and testability. The following section correlates maintainability metrics with these two specific areas and also provides a general assessment of metrics for maintainability in terms of this project. Analyzability and Testability The analyzability of a piece of software is based on a number of factors and cannot be entirely reduced to the syntactical issues that software metrics reveal. Nevertheless, there are many issues that contribute to analyzability that can be related to a software metric. The coupling between classes is one of the more significant issues in analyzability. This is because in order to

MAINTENANCE AT THE NORTH POLE

71

understand the behavior of a single class, it is necessary to understand all of the classes that are directly coupled to this class. There are several methods for dealing with coupling, but not all of them also solve the problem of analyzability because in some cases they may actually complicate the software and further obscure the behavior of a class. The vocabulary metric is also a significant contributor to the analyzability of a piece of software. Each increase in program vocabulary can be equated with one more area of knowledge for the developer who is analyzing the codebase. The lines of code and volume metrics are related but slightly less significant in terms of the analyzability of the software. These metrics will define the amount of time necessary to gain an understanding of the whole software system, but if the volume of the software consists of a relatively limited vocabulary, it is not necessarily more difficult to analyze a longer program. The two areas that most affect the testability of the software are the efferent coupling and the logical complexity measurements. Each logical branch represents one or two extra tests that must be added to have complete coverage of the codebase with unit tests. In terms of nonautomated testing an extra branch in logic will equal extra time spent in writing test plans and executing them. It will also increase the risk that a tester will not be able to discover a bug in the software. The efferent coupling represents the number of external classes or components that a piece of software depends on. In terms of testability this means that there is a decrease in the ability to cover a particular class using unit testing. There are solutions such as stubbing and mocking that can help to compensate for dependencies, but both represent extra testing effort. In addition, if the software is being manually tested, an additional coupling may mean that the tester needs to setup an additional area of the program for testing. This is not the case with the example

MAINTENANCE AT THE NORTH POLE

72

used in this thesis. The challenge in coupling between classes was in creating synchronization errors. General Analysis One of the motivating questions for this thesis is how applicable the traditional software metrics are to evaluating the maintainability of concurrent software. If they are not applicable, this raises the question of whether any metrics at all could be used to evaluate to concurrent software. The results section as well as the first part of this chapter point to a well-delimited area of application for software metrics, even in terms of concurrent software. The first area in which these metrics are useful is in pointing out general trends in software evolution. The second area is in aggregating syntactical issues that are not entirely evident from simply examining the design and implementation of the software. The metrics were also useful for the goal of this thesis, which was in giving a way to ground a comparison of concurrency paradigms in terms of software maintainability. Some of Halsteads metrics, especially those that are derived mathematically rather than directly from the code, are difficult to attribute to any particular software trend. However, the Halstead vocabulary metric was useful in identifying the level and reusability of the abstraction in the software. The coupling metrics also identified a major concern in software design. The level of growth in this metric also showed correlation to the level of change that would be necessary to implement a new feature in the software. The complexity metric also was useful in identifying a characteristic difference between the pure Java implementations and the message passing concurrency implementations. The design documents and the coding process itself gave the impression that the Java version would be more complex, more highly coupled, and more difficult to maintain. However

MAINTENANCE AT THE NORTH POLE

73

the results from the metrics prompted a reevaluation of the Java version. The Java version was able to make use of language features that resulted in more concise and less complex syntax. These results gathered from the metrics indicate that metrics are most useful when they are directed towards gaining specific knowledge about software. This means that looking at averaged or combined metrics is less useful in evaluating software. A general maintainability index would not be able to indicate the actual area of the software that needs to be corrected. It also would not be useful for deriving points of comparison for evaluating general software design. The method of analysis also indicates that metrics are most useful when combined with an analysis of the design artifacts and actual code in consideration. While metrics can help to identify issues that may be revealed through syntax, they do not reveal every important aspect of what makes a piece of software more easily comprehensible, and hence maintainable. One example of this was the general analyzability of a piece of software that could be achieved by having a more atomic approach to the program algorithm. The final question is whether a separate type of metrics is necessary for the study of concurrent software. The evidence of this project does not suggest that a separate metric is needed for the purpose of evaluating the maintainability of concurrent software. The existing metrics were able to point out relevant trade-offs that existed in the software versions under study. In particular, in concurrent software the true complexity is the result of interactions between software components rather than solely located in the complexity measured in logical branching. This means that the maintainability of concurrent software should be evaluated as a function of coupling and cyclomatic complexity. Also this study revealed that the maintainability of concurrent software was related to the ability to capture a method of concurrent interaction in

MAINTENANCE AT THE NORTH POLE

74

a reusable abstraction. The Halstead metrics for unique operands and the combination in the vocabulary metric was useful for measuring this factor. Conclusions This thesis was intended to discover issues in software evolution that resulted from the development of concurrent software. In order to accomplish this both the software itself and the commonly available methods for analyzing software maintainability were considered. The result of this type of investigation was to discover areas of consilience. The literature review revealed that in the area of software engineering, significant effort has been directed towards creating higher-level constructs for concurrent software. This effort is in the hope that concurrent software will be easier to both develop and maintain. However, in defining these goals, the primary selling point of each solution is that it in some way reduces complexity. This goal would be more useful if defined in terms of a more specific aim, whether to reduce syntactic, logical, or design complexity. Another issue that was revealed in the literature review was the question of whether the development of software metrics in order to evaluate software quality was useful in terms of software maintainability. Several studies found correlations between real time spent in maintenance or the expert opinion of software engineers and the results obtained from software metrics. Other scholars have criticized metrics at best a coarse approximation of software quality and at worst having no relation to the actual factors that contribute to software maintainability. This thesis contains an experiment that is intended to explore the issue raised by these claims. In order to explore the first area, three different versions of behaviorally equivalent software were developed using three leading paradigms of concurrent software. The first version to be considered was developed in pure Java using the languages built-in concurrency features,

MAINTENANCE AT THE NORTH POLE

75

particularly the classes in the java.util.concurrent package and the Java threading model. The second version was developed using JCSP, which is a Java implementation of the theory of Communicating Sequential Processes. The final version was developed using the Akka framework, which is a contemporary realization of the actor model for JVM languages. These three versions were subjected to comparable tests of maintainability over four sets of feature additions. In order to assess the applicability of maintainability metrics the three versions were analyzed in terms of several key software metrics for each of the five iterations. The resulting metrics were first interpreted in terms of the actual code base. Later the cumulative results were analyzed in terms of three conceptual areas related to concurrency and maintainability. It was found that software metrics could be useful in conceptualizing, measuring, and articulating the factors that made concurrent software more or less maintainable. It was also found that metrics were more useful when used in the context of a general assessment of design principles and a knowledge of the actual source code. It was also discovered that the more specifically a metric could be tier to features in the source code, the more useful it was in analyzing the quality of the software. This generally excludes mass aggregates and indexes from being used for this sort of analysis. Finally, this thesis did not discover that there were any clearly more maintainable solutions. Rather there were several key trade-offs that gave each approach an advantage in a particular aspect of software maintainability. The pure Java version exhibited a lesser degree of logical complexity and a lower overall code volume due to utilizing the languages built in features. The Akka and JCSP versions exhibited a lower degree of growth in the area of coupling, which made the addition of features require less changes to the code. The Akka and JCSP versions also exhibited a unified abstraction that resulted in less growth in code

MAINTENANCE AT THE NORTH POLE

76

vocabulary, and hence a more maintainable code comprehensibility. The JCSP version also exhibited an atomicity of the process that made it easier to reason about the sequence of the entire solution algorithm. The Akka version benefitted from its asynchronous communication model. This allowed for a separation of concerns when adding a feature that needed additional types of communication and required a particular object state for communication response. There are several areas that could be studied further that were not included in this thesis. First of all, a similar comparison could be made between languages that have these concurrency paradigms as first-class citizens. One of the reasons for Javas widespread use and good performance in a variety of situations is its built in support for in-process concurrency. There are several languages that also have this attribute, such as Go, Scala, Clojure, Erlang, and the newly developed Elixir. This may do away with the impedance gained from needing to make use of a library. Another type of study would be to try to develop metrics specifically for measuring the types of trade-offs addressed in the analysis section as well as an automated way to compute them. Finally a study could be devoted more exclusively to the semantic issues in concurrency. This is one area that was only hinted at in this thesis, and could be more explicitly defined in the literature.

MAINTENANCE AT THE NORTH POLE Appendix A. Complete Code of Programs

77

The server side code is reproduced here. The front-end resources (html, javascript, css) are entirely decoupled from the server implementation and thus are not relevant to the thesis project. Shared Classes These classes are identical between all program versions. Util.Data.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package Util; import java.io.*; public final class Data implements Serializable { private private private private String String String String message; who; type; author;

public Data() { this("", ""); } public Data(String who, String message) { this.who = who; this.message = message; } public String getMessage() { return message; } public String getWho() { return who; } public void setWho(String who) { this.who = who; } public void setMessage(String message) { this.message = message; } public void setType(String type){ this.type = type; } public String getType(){ return type; } public void setAuthor(String author){ this.author = author; } public String getAuthor(){ return author; } public byte[] toByteArray(){ ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = null; byte[] bytes = null; try {

MAINTENANCE AT THE NORTH POLE


58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 out = new ObjectOutputStream(bos); out.writeObject(this); bytes = bos.toByteArray(); } catch (Exception e){ e.printStackTrace(); } finally { try { out.close(); bos.close(); } catch (IOException e) { e.printStackTrace(); } } return bytes; } public static Data buildFromBytes(byte[] data){ ByteArrayInputStream bis = new ByteArrayInputStream(data); ObjectInput in = null; Object o = null; try { in = new ObjectInputStream(bis); o = in.readObject(); } catch (Exception e) { e.printStackTrace(); } finally { try { bis.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } } return (Data)o; } }

78

Server.NettoServer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package Server; import org.atmosphere.nettosphere.Config; import org.atmosphere.nettosphere.Nettosphere; public class NettoServer { public NettoServer(){ Config.Builder b = new Config.Builder(); b.resource(NorthPole.class) .resource("./src/main/resources") .port(8080).host("127.0.0.1").build(); Nettosphere s = new Nettosphere.Builder().config(b.build()).build(); s.start(); } }

Pure Java Version NorthPole Package NorthPole.java


1 2 3 4 5 package NorthPole; import Server.NettoServer; import WishList.WishList;

MAINTENANCE AT THE NORTH POLE


6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class NorthPole { public static void main (String[] args){ final final final final final final SnackRoom sr = new SnackRoom(); Santa santa = new Santa(sr); MrsClaus mrsClaus = new MrsClaus(sr); WaitingRoom waitingRoom = new WaitingRoom(santa, 3, "Elf"); WaitingRoom stable = new WaitingRoom(santa, 9, "Reindeer"); String[] reindeerNames = { "Dasher","Dancer", "Prancer", "Vixen", "Comet","Cupid","Donder","Blitzen","Ruldolph" }; final String[] elfNames = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" }; santa.findWaitingRoom(waitingRoom); santa.findStable(stable); (new Thread(santa)).start(); for (String name : reindeerNames){ (new Thread(new SantasFriend(name, stable, "Reindeer"))).start(); } for (String name : elfNames){ (new Thread(new SantasFriend("Elf" + name, waitingRoom, "Elf"))).start(); } (new Thread(mrsClaus)).start(); } }

79

NorthPoleConcurrentObject.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package NorthPole; import Util.Data; import Util.OutputService; public class NorthPoleConcurrentObject extends Thread{ String name; private final OutputService outPrint; NorthPoleConcurrentObject(String name){ outPrint = new OutputService("5565"); this.name = name; } @Override public void run(){} public void log(String message){ System.out.println(name + ": " + message); outPrint.send(new Data(name, message)); } public void log(String n, String message){ System.out.println(n + ": " + message); outPrint.send(new Data(n, message)); } }

SantasFriend.java
1 2 3 4 5 6 7 8 9 10 11 12 package NorthPole; import java.util.Random; import java.util.concurrent.SynchronousQueue; public class SantasFriend extends NorthPoleConcurrentObject { private Random randomGenerator = new Random(); private final WaitingRoom waitingRoomRef; public final String type; SynchronousQueue<Integer> wait = new SynchronousQueue<Integer>(); SantasFriend (String name, WaitingRoom waitingRoomRef, String type){

MAINTENANCE AT THE NORTH POLE


13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 super(name); this.waitingRoomRef = waitingRoomRef; this.type = type; } public void withSanta() throws InterruptedException{ wait.take(); } public void doneWithSanta() throws InterruptedException{ wait.put(1); } @Override public void run(){ try{ Thread.sleep(randomGenerator.nextInt(100) * 200); } catch (Exception e) {log("Interrupted exception");} while(true){ try{ Thread.sleep(randomGenerator.nextInt(100) * 200); log("Working"); if (waitingRoomRef.receiveVisitor(this).equals("RoomFull")){ log("Waiting room is full"); Thread.sleep(randomGenerator.nextInt(100) * 200); } else{ log ("In the waiting room"); withSanta(); log("Going to work"); Thread.sleep(randomGenerator.nextInt(100) * 200); } } catch (InterruptedException e) {log("Interrupted exception");} } } }

80

Santa.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package NorthPole; import Util.Data; import Util.OutputService; import import import import java.util.concurrent.BrokenBarrierException; java.util.concurrent.CyclicBarrier; java.util.concurrent.ExecutorService; java.util.concurrent.Executors;

public class Santa extends NorthPoleConcurrentObject{ private WaitingRoom waitingRoom; private WaitingRoom stable; private Boolean isSleeping; private final SnackRoom sr; private final ExecutorService es = Executors.newSingleThreadExecutor(); private final OutputService outDeliver; public Santa(SnackRoom sr){ super("Santa"); outDeliver = new OutputService("5566"); this.sr = sr; } public void findWaitingRoom(WaitingRoom waitingRoom){ this.waitingRoom = waitingRoom; } public void findStable(WaitingRoom stable){ this.stable = stable; }

MAINTENANCE AT THE NORTH POLE

81

32 public void sleep() throws InterruptedException{ 33 log("Sleeping"); 34 isSleeping = true; 35 } 36 37 public Boolean wake() throws InterruptedException, BrokenBarrierException{ 38 if (stable.isWaiting && isSleeping){ 39 deliverToys(stable.group); 40 return true; 41 } 42 if (waitingRoom.isWaiting && isSleeping){ 43 consultOnRD(waitingRoom.group); 44 return true; 45 } 46 return false; 47 } 48 49 public void deliverToys(Group reindeer) throws InterruptedException, BrokenBarrierException{ 50 CyclicBarrier work = new CyclicBarrier(2); 51 isSleeping = false; 52 log("Harnessing reindeer"); 53 es.submit(new UnitOfWork("Getting Hitched", reindeer, work)); 54 es.submit(new UnitOfWork("Delivering Toys", reindeer, work)); 55 outDeliver.send(new Data("", "Deliver")); 56 es.submit(new UnitOfWork("Getting unhitched", reindeer, work)); 57 es.submit(new UnitOfWork("Release", reindeer, work)); 58 work.await(); 59 log("Unharnessing reindeer"); 60 stable.releaseGroup(); 61 sleep(); 62 } 63 64 public void consultOnRD(Group elves) throws InterruptedException, BrokenBarrierException{ 65 sr.isWithElves(); 66 CyclicBarrier work = new CyclicBarrier(2); 67 isSleeping = false; 68 log("Welcoming elves"); 69 if(sr.isWaiting()) eatCookies(); 70 es.submit(new UnitOfWork("Entering Santa's house", elves, work)); 71 if(sr.isWaiting()) eatCookies(); 72 log("Consulting with elves"); 73 es.submit(new UnitOfWork("Consulting with Santa", elves, work)); 74 if(sr.isWaiting()) eatCookies(); 75 log("Dismissing Elves"); 76 es.submit(new UnitOfWork("Leaving santa's", elves, work)); 77 if(sr.isWaiting()) eatCookies(); 78 es.submit(new UnitOfWork("Release", elves, work)); 79 if(sr.isWaiting()) eatCookies(); 80 work.await(); 81 waitingRoom.releaseGroup(); 82 sr.doneMeeting(); 83 sleep(); 84 } 85 private void eatCookies(){ 86 try { 87 log("Eating Cookies"); 88 Thread.sleep(1000); 89 } catch (InterruptedException e) { 90 e.printStackTrace(); 91 } 92 sr.doneEating(1); 93 } 94 95 @Override 96 public void run(){ 97 try{ 98 sleep(); 99 } 100 catch (InterruptedException e) { 101 System.out.println("Interrupted exception at Santa"); 102 }

MAINTENANCE AT THE NORTH POLE


103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 } class UnitOfWork implements Runnable{ CyclicBarrier work; final String name; final Group visitors; public UnitOfWork(String name, Group visitors, CyclicBarrier work){ this.work = work; this.name = name; this.visitors = visitors; } public void run(){ try { Thread.sleep(2000); if (name.equals("Release")) visitors.releaseGroup(work); else visitors.groupActivity(this, work); } catch (InterruptedException e) { System.out.println("Interrupted exception at UnitOfWork");} catch (BrokenBarrierException e) { System.out.println("Barrier exception at UnitOfWork"); } } } }

82

Group.java
1 package NorthPole; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 import java.util.concurrent.BrokenBarrierException; 6 import java.util.concurrent.CyclicBarrier; 7 import java.util.concurrent.LinkedBlockingQueue; 8 9 public class Group extends NorthPoleConcurrentObject{ 10 11 private LinkedBlockingQueue<SantasFriend> group; 12 int size; 13 final public String type; 14 private ArrayList<String> names = new ArrayList<String>(); 15 16 Group(int i, String type){ 17 super(type); 18 group = new LinkedBlockingQueue<SantasFriend>(i); 19 size = i; 20 this.type = type; 21 } 22 23 public void add(SantasFriend friend) throws InterruptedException{ 24 names.add(friend.name); 25 group.put(friend); 26 } 27 28 public int getSize(){ 29 return group.size(); 30 } 31 32 public void releaseGroup(CyclicBarrier work) throws BrokenBarrierException { 33 Iterator<SantasFriend> groupList = group.iterator(); 34 names.clear(); 35 while(groupList.hasNext()){ 36 groupList.next().doneWithSanta(); 37 } 38 group.clear(); 39 work.await(); 40 } 41

InterruptedException,

MAINTENANCE AT THE NORTH POLE

83

42 public void groupActivity (Santa.UnitOfWork unitOfWork, CyclicBarrier work) throws InterruptedException, BrokenBarrierException { 43 Thread.sleep(2000); 44 for (String name : names){ 45 log(name, unitOfWork.name); 46 } 47 } 48 }

WaitingRoom.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 package NorthPole; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class WaitingRoom { public Group group; public Boolean isWaiting; ExecutorService es = Executors.newSingleThreadExecutor(); final Santa santaRef; public void releaseGroup() throws InterruptedException{ isWaiting = false; } WaitingRoom(Santa santaRef, int size, String type){ this.santaRef = santaRef; group = new Group(size, type); isWaiting = false; (new Thread(group)).start(); } public String receiveVisitor(SantasFriend e) throws InterruptedException{ if (group.getSize() < group.size && !isWaiting){ group.add(e); if (group.getSize() == group.size){ isWaiting = true; es.submit(new MeetSanta(group, group.type)); } return "Waiting"; } else{ return "RoomFull"; } } class MeetSanta implements Runnable { String type; Group group; MeetSanta(Group group, String type){ this.type = type; this.group = group; } public void run(){ Boolean found = false; while(!found) { try{ found = santaRef.wake(); } catch (InterruptedException e){ System.out.println("Interrupted exception at WaitingRoom");} catch (BrokenBarrierException e) { System.out.println("Barrier exception at WaitingRoom");} } } } }

MAINTENANCE AT THE NORTH POLE

84

MrsClaus.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package NorthPole; public class MrsClaus extends NorthPoleConcurrentObject{ public MrsClaus(SnackRoom sr){ super("MrsClaus"); this.sr = sr; } final private SnackRoom sr; final private String name = "MrsClaus"; @Override public void run() { while (true){ try { Thread.sleep(5000); log("Going to Santa's"); Thread.sleep(10000); log("Waiting with cookies"); sr.waitWithCookies(); } catch (java.lang.InterruptedException e) { e.printStackTrace(); } log("Done with Cookies"); } } }

SnackRoom.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package NorthPole; import java.util.concurrent.LinkedBlockingQueue; public class SnackRoom { private Boolean santaIsWithElves = false; private Boolean mrsClausIsWaiting = false; private LinkedBlockingQueue<Integer> wait = new LinkedBlockingQueue<Integer>(); public SnackRoom(){} public Boolean isWaiting(){ return mrsClausIsWaiting; } public Boolean isWithElves(){ return santaIsWithElves; } public Integer waitWithCookies(){ mrsClausIsWaiting = true; Integer a = null; try { a = wait.take(); } catch (InterruptedException e) { e.printStackTrace(); } return a; } public void setMeeting(){ santaIsWithElves = true;

MAINTENANCE AT THE NORTH POLE


34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 } public void doneMeeting(){ santaIsWithElves = false; } public void doneEating(Integer a){ mrsClausIsWaiting = false; try { wait.put(a); } catch (InterruptedException e) { e.printStackTrace(); } } }

85

WishList Package RunWishList.java


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package WishList; import Util.InputService; import Util.OutputService; public class RunWishList { public static void main(String[] args){ OutputService out = new OutputService("5564"); WishList wishList = new WishList(out); new Thread(new InputService(wishList, "5563")).start(); new Thread(new InputService(wishList, "5566")).start(); } }

WishList.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package WishList; import Util.Command; import Util.Data; import Util.OutputService; import java.util.concurrent.CopyOnWriteArrayList; public final class WishList implements Command { private static CopyOnWriteArrayList<Data> wishList = new CopyOnWriteArrayList<Data>(); OutputService out; public WishList(OutputService out){ this.out = out; } public void deliverGifts(){ String output = "["; System.out.println("Gifts for: "); for(Data d : wishList){ output += "\"" + d.getAuthor() + " : " + d.getMessage() + "\","; } wishList.clear(); output = output.substring(0,output.length() - 1) + "]"; System.out.println(output); Data data = new Data("all", output); data.setType("Delivery"); out.send(data); } public static void addToWishList(Data msg){

MAINTENANCE AT THE NORTH POLE


33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 if(msg.getType().equals("wishlist")){ wishList.add(msg); System.out.println(msg.getMessage()); } } @Override public void execute() {} @Override public void execute(Data data) { if(data.getMessage().equals("Deliver")) deliverGifts(); else addToWishList(data); } }

86

Server Package RunServer.java


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package Server; import import import import Util.InputService; Util.OutputService; java.lang.String; java.lang.Thread;

public class RunServer { public static void main(String[] args){ NettoServer ns = new NettoServer(); OutputService out = new OutputService("5563"); BroadcastOutMain broadcast = new BroadcastOutMain(); NorthPole.SendToOutput.out = out; new Thread(new InputService(broadcast, "5564")).start(); new Thread(new InputService(broadcast, "5565")).start(); } }

NorthPole.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package Server; import import import import import import import import import import Util.Data; Util.OutputService; org.atmosphere.config.service.Get; org.atmosphere.config.service.ManagedService; org.atmosphere.config.service.Message; org.atmosphere.cpr.AtmosphereResource; org.atmosphere.cpr.Broadcaster; org.atmosphere.cpr.BroadcasterFactory; org.codehaus.jackson.map.ObjectMapper; java.io.IOException;

@ManagedService(path = "/northpole") public class NorthPole { private final ObjectMapper mapper = new ObjectMapper(); Broadcaster b = BroadcasterFactory.getDefault().get("/"); @Get public void onOpen(final AtmosphereResource r) { b.addAtmosphereResource(r); } @Message

MAINTENANCE AT THE NORTH POLE


26 27 28 29 30 31 32 33 34 35 public String onMessage(String message) throws IOException { Data d = mapper.readValue(message, Data.class); SendToOutput.out.send(d); return mapper.writeValueAsString(d); } public static class SendToOutput{ public static OutputService out; } }

87

BroadCastOutMain.java
1 package Server; 2 3 import Util.Command; 4 import Util.Data; 5 import org.atmosphere.cpr.Broadcaster; 6 import org.atmosphere.cpr.BroadcasterFactory; 7 8 import java.util.concurrent.Future; 9 10 public class BroadcastOutMain implements Command { 11 Broadcaster b; 12 public BroadcastOutMain(){ 13 this.b = BroadcasterFactory.getDefault().lookup("/"); 14 } 15 16 public void send(Data data) { 17 Future br = b.broadcast("{\"message\": " + wrapInQuotes(data) + "," + 18 "\"who\":\""+data.getWho()+"\","+ 19 "\"type\":\"northPole\"}"); 20 } 21 22 private String wrapInQuotes(Data data){ 23 return ("Delivery".equals(data.getType()) ? data.getMessage() data.getMessage()+ "\" " ); 24 } 25 26 @Override 27 public void execute() { 28 29 } 30 31 @Override 32 public void execute(Data data) { 33 send(data); 34 } 35 }

"\""

Util Package Command.java


1 2 3 4 5 5 6 7 package Util; import Util.Data; public interface Command { void execute(); void execute(Data data); }

InputService.java

MAINTENANCE AT THE NORTH POLE


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package Util; import org.jeromq.ZMQ; public class InputService implements Runnable{ Command cmd; String port; ZMQ.Context context; ZMQ.Socket subscriber; public InputService(Command cmd, String port){ this.cmd = cmd; this.port = port; context = ZMQ.context(1); subscriber = context.socket(ZMQ.PULL); subscriber.bind("tcp://*:"+port); } public void run() { while (!Thread.currentThread ().isInterrupted ()) { Data contents = Data.buildFromBytes(subscriber.recv()); cmd.execute(contents); } subscriber.close(); context.term(); } }

88

OutputService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package Util; import org.jeromq.ZMQ; public class OutputService { private ZMQ.Socket publisher; private ZMQ.Context context; final String port; public OutputService(String port){ this.port = port; context = ZMQ.context(1); publisher = context.socket(ZMQ.PUSH); publisher.connect("tcp://localhost:"+port); } public void send(Data data){ publisher.send(data.toByteArray()); } }

MAINTENANCE AT THE NORTH POLE JCSP Version JCSPNorthPole Package Main.java

89

1 package JCSPNorthPole; 2 3 import Util.JCSPNetworkServiceIn; 4 import org.jcsp.lang.*; 5 import java.util.List; 6 7 public class Main { 8 enum name{ Dasher, Dancer, Prancer, Vixen, Comet, 9 Cupid, Donder, Blitzen, Ruldolph } 10 public static void main(String[] args) 11 { 12 AltingBarrier [] stable = AltingBarrier.create(10); 13 AltingBarrier [] sleigh = AltingBarrier.create(10); 14 Bucket elfGroup = new Bucket(); 15 Bucket cookieRoom = new Bucket(); 16 One2OneChannel openForBusiness = Channel.one2one(); 17 One2OneChannel consultationOver = Channel.one2one(); 18 Any2OneChannel harness = Channel.any2one(); 19 One2AnyChannel harnessed = Channel.one2any(); 20 One2AnyChannel returned = Channel.one2any(); 21 One2OneChannel[] unharness = Channel.one2oneArray(9); 22 List<ChannelOutput> unharnessList = Utils.getOutList(unharness); 23 Any2OneChannel needToConsult = Channel.any2one(); 24 One2AnyChannel joinGroup = Channel.one2any(); 25 Any2OneChannel consult = Channel.any2one(); 26 Any2OneChannel negotiating = Channel.any2one(); 27 One2OneChannel[] consulting = Channel.one2oneArray(10); 28 One2OneChannel[] consulted = Channel.one2oneArray(10); 29 List<ChannelOutput> consultingList = Utils.getOutList(consulting); 30 List<ChannelOutput> consultedList = Utils.getOutList(consulted); 31 Any2OneChannel print = Channel.any2one(); 32 One2OneChannel deliveryNotice = Channel.one2one(); 33 34 CSProcess[] reindeerProc = new CSProcess[9]; 35 for (name r : name.values()){ 36 reindeerProc[r.ordinal()] = new Reindeer(r.toString(), stable[r.ordinal()], sleigh[r.ordinal()], 37 harness.out(), harnessed.in(), returned.in(), 38 unharness[r.ordinal()].in(), print.out()); 39 } 40 41 CSProcess[] elfProc = new CSProcess[10]; 42 for (int i = 1; i <= 10; i++){ 43 elfProc[i-1] = new Elf("Elf" + String.valueOf(i), i-1, elfGroup, needToConsult.out(), joinGroup.in(), 44 consult.out(), consulting[i-1].in(), negotiating.out(), consulted[i-1].in(), 45 print.out()); 46 } 47 48 CSProcess[] procs = {new Santa(openForBusiness.out(), consultationOver.out(),harness.in(), harnessed.out(), 49 returned.out(), unharnessList,stable[9],sleigh[9],consult.in(), 50 consultingList,negotiating.in(), consultedList, print.out(), 51 cookieRoom, deliveryNotice.out()), 52 new WaitingRoom(elfGroup,needToConsult.in(),joinGroup.out(), 53 openForBusiness.in(),consultationOver.in()), 54 new MrsClaus(cookieRoom, print.out()), 55 new JCSPNetworkServiceIn(print.in(), "5566"), 56 new JCSPNetworkServiceIn(deliveryNotice.in(), "5564") 57 };

MAINTENANCE AT THE NORTH POLE


58 59 60 61 62 63

90

procs = Utils.concat(procs, reindeerProc); procs = Utils.concat(procs, elfProc); new Parallel(procs).run(); } }

Utils.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package JCSPNorthPole; import org.jcsp.lang.CSProcess; import org.jcsp.lang.ChannelOutput; import org.jcsp.lang.One2OneChannel; import java.util.ArrayList; import java.util.List; public class Utils {

public static CSProcess[] concat(CSProcess[] A, CSProcess[] B) { int aLen = A.length; int bLen = B.length; CSProcess[] C = new CSProcess[aLen+bLen]; System.arraycopy(A, 0, C, 0, aLen); System.arraycopy(B, 0, C, aLen, bLen); return C; } public static List<ChannelOutput> getOutList(One2OneChannel[] chan){ List<ChannelOutput> outs = new ArrayList<ChannelOutput>(); for(int i = 0; i < chan.length; i++){ outs.add(chan[i].out()); } return outs; } }

NorthPoleProcess.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package JCSPNorthPole; import Util.Data; import org.jcsp.lang.CSProcess; import org.jcsp.lang.ChannelOutput; public class NorthPoleProcess implements CSProcess { String name; ChannelOutput print; NorthPoleProcess(String name, ChannelOutput print){ this.name = name; this.print = print; } @Override public void run() {} public void log(String s){ print.write(new Data(name,s)); System.out.println(name + " : " + s); } }

Elf.java
1 2 3 4 5 package JCSPNorthPole; import org.jcsp.lang.*; import java.util.Random;

MAINTENANCE AT THE NORTH POLE


6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

91

public class Elf extends NorthPoleProcess{ int number; Bucket group; ChannelOutput needToConsult; ChannelInput joinGroup; ChannelOutput consult; ChannelInput consulting; ChannelOutput negotiating; ChannelInput consulted; public Elf(String name, int number, Bucket group, ChannelOutput needToConsult, ChannelInput joinGroup,ChannelOutput consult, ChannelInput consulting, ChannelOutput negotiating, ChannelInput consulted, ChannelOutput print){ super(name, print); this.number = number; this.group = group; this.needToConsult = needToConsult; this.joinGroup = joinGroup; this.consult = consult; this.consulting = consulting; this.negotiating = negotiating; this.consulted = consulted; } int workingTime = 3; @Override public void run(){ Random rng = new Random(); CSTimer timer = new CSTimer(); while(true){ log("Working"); timer.sleep(workingTime + rng.nextInt(workingTime)); needToConsult.write(number); Integer join = (Integer)joinGroup.read(); if(join == 1) { group.fallInto(); log ("In the waiting room"); consult.write(number); log("Entering Santa's house"); consulting.read(); log("Consulting with Santa"); negotiating.write(1); consulted.read(); log("Leaving santa's"); } else { log("Waiting room is full"); timer.sleep(workingTime + rng.nextInt(workingTime)); } } } }

Reindeer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package JCSPNorthPole; import org.jcsp.lang.*; import java.util.Random; public class Reindeer extends NorthPoleProcess{ AltingBarrier stable; AltingBarrier sleigh; ChannelOutput harness; ChannelInput harnessed; ChannelInput returned; ChannelInput unharness;

MAINTENANCE AT THE NORTH POLE


15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 int holidayTime = 4000; public Reindeer(String name, AltingBarrier stable, AltingBarrier sleigh, ChannelOutput harness, ChannelInput harnessed, ChannelInput returned, ChannelInput unharness, ChannelOutput print){ super(name, print); this.stable = stable; this.sleigh = sleigh; this.harness = harness; this.harnessed = harnessed; this.returned = returned; this.unharness = unharness; } @Override public void run(){ Random rng = new Random(); CSTimer timer = new CSTimer(); while (true) { log("Going on Vacation"); timer.sleep(holidayTime + rng.nextInt(holidayTime)); log("Back from vacation"); stable.sync(); harness.write(name); log("Getting Hitched"); harnessed.read(); sleigh.sync(); log("Delivering Toys"); returned.read(); log("Getting unhitched"); unharness.read(); } } }

92

Santa.java
1 package JCSPNorthPole; 2 3 import Util.Data; 4 import org.jcsp.lang.*; 5 import java.util.List; 6 import java.util.Random; 7 8 public class Santa extends NorthPoleProcess { 9 10 final ChannelOutput openForBusiness; 11 final ChannelOutput consultationOver; 12 final ChannelInput harness; 13 final ChannelOutput harnessed; 14 final ChannelOutput returned; 15 final List<ChannelOutput> unharnessList; 16 final AltingBarrier stable; 17 final AltingBarrier sleigh; 18 final AltingChannelInput consult; 19 final List<ChannelOutput> consulting; 20 final ChannelInput negotiating; 21 final List<ChannelOutput> consulted; 22 final Bucket cookiesReady; 23 final int deliveryTime = 5000; 24 final int consultationTime = 2000; 25 final ChannelOutput delivery; 26 27 public Santa(ChannelOutput openForBusiness, ChannelOutput consultationOver, ChannelInput harness, ChannelOutput harnessed, 28 ChannelOutput returned, List<ChannelOutput> unharnessList, AltingBarrier stable, AltingBarrier sleigh, 29 AltingChannelInput consult, List<ChannelOutput> consulting, ChannelInput negotiating, 30 List<ChannelOutput> consulted, ChannelOutput print, Bucket cookiesReady, ChannelOutput delivery){ 31 super("Santa", print);

MAINTENANCE AT THE NORTH POLE


32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 this.openForBusiness = openForBusiness; this.consultationOver = consultationOver; this.harness = harness; this.harnessed = harnessed; this.returned = returned; this.unharnessList = unharnessList; this.stable = stable; this.sleigh = sleigh; this.consult = consult; this.consulting = consulting; this.negotiating = negotiating; this.consulted = consulted; this.cookiesReady = cookiesReady; this.delivery = delivery; } @Override public void run(){ Random rng = new Random(); CSTimer timer = new CSTimer(); Guard[] guards = {stable, consult}; Alternative santaAlt = new Alternative(guards); openForBusiness.write(1); while (true) { int index = santaAlt.priSelect(); switch (index) { case 0 : //Reindeer String[] id = new String[9]; log("Harnessing reindeer"); for ( int i = 0; i <= 8; i++){ id[i] = (String)harness.read(); } for ( int i = 0; i <= 8; i++){ harnessed.write(1); } sleigh.sync(); delivery.write(new Data()); timer.sleep ( deliveryTime + rng.nextInt(deliveryTime)); for ( int i = 0; i <= 8; i++){ returned.write(1); } log("Unharnessing reindeer"); for ( int i = 0; i <= 8; i++) { unharnessList.get(i).write(1); } break; case 1: //Elves Integer[] id2 = new Integer[9]; if (cookiesReady.holding() > 0) { log("Eating Cookies"); timer.sleep(2000); cookiesReady.flush(); } id2[0] = (Integer)consult.read(); log("Welcoming elves"); if (cookiesReady.holding() > 0) { log("Eating Cookies"); timer.sleep(2000); cookiesReady.flush(); log("Welcoming elves"); } for ( int i = 1; i <= 2; i++) { id2[i] = (Integer)consult.read(); } for ( int i = 0; i <= 2; i++) { consulting.get(id2[i]).write(1); } for ( int i = 0; i <= 2; i++) { negotiating.read(); } timer.sleep ( consultationTime + rng.nextInt(consultationTime)); log("Showing elves out"); if (cookiesReady.holding() > 0) { log("Eating Cookies"); timer.sleep(2000); cookiesReady.flush(); log("Showing elves out"); } for ( int i = 0; i <= 2; i++){ consulted.get(id2[i]).write(1); }

93

MAINTENANCE AT THE NORTH POLE


105 106 107 108 109 110 consultationOver.write(1); break; } } } }

94

MrsClaus.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package JCSPNorthPole; import org.jcsp.lang.Bucket; import org.jcsp.lang.CSTimer; import org.jcsp.lang.ChannelOutput; public class MrsClaus extends NorthPoleProcess { private final Bucket deliverCookies; private final String name = "MrsClaus"; private final CSTimer timer = new CSTimer(); MrsClaus(Bucket deliverCookies, ChannelOutput print){ super("MrsClaus", print); this.deliverCookies = deliverCookies; } @Override public void run() { while(true){ log("Going to Santa's"); timer.sleep(10000); log("Waiting with Cookies"); deliverCookies.fallInto(); log("Leaving Santa's"); timer.sleep(5000); } } }

WaitingRoom.java
1 package JCSPNorthPole; 2 3 import org.jcsp.lang.*; 4 5 public class WaitingRoom extends NorthPoleProcess { 6 7 Bucket group; 8 AltingChannelInput needToConsult; 9 ChannelOutput joinGroup; 10 AltingChannelInput openForBusiness; 11 AltingChannelInput consultationOver; 12 13 public WaitingRoom( Bucket group, AltingChannelInput needToConsult, ChannelOutput joinGroup, 14 AltingChannelInput openForBusiness, AltingChannelInput consultationOver){ 15 super("", null); 16 this.group = group; 17 this.needToConsult = needToConsult; 18 this.joinGroup = joinGroup; 19 this.openForBusiness = openForBusiness; 20 this.consultationOver = consultationOver; 21 } 22 23 @Override 24 public void run(){ 25 Skip flush = new Skip(); 26 Guard[] guards = { needToConsult, consultationOver, flush }; 27 Alternative vAlt = new Alternative(guards); 28 int index = -1;

MAINTENANCE AT THE NORTH POLE


29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 int counter = 0; boolean[] preCon = { true, true, false }; openForBusiness.read(); while (true){ index = vAlt.select(preCon); switch (index) { case 0: //Need needToConsult.read(); if (counter < 3){ joinGroup.write(1); counter = counter + 1; } else { joinGroup.write(0); } break; case 1: //Over consultationOver.read(); break; case 2: //Flush group.flush(); counter = 0; break; } preCon[2] = (group.holding() == 3); } } }

95

WishListProcess Package StartWishList.java


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package WishListProcess; import import import import import import Util.JCSPNetworkServiceIn; Util.JCSPNetworkServiceOut; org.jcsp.lang.CSProcess; org.jcsp.lang.Channel; org.jcsp.lang.One2OneChannel; org.jcsp.lang.Parallel;

public class StartWishList { public static void main(String[] args){ One2OneChannel delivery = Channel.one2one(); One2OneChannel wish = Channel.one2one(); One2OneChannel printOut = Channel.one2one(); CSProcess[] procs = { new WishList(wish.in(), delivery.in(), printOut.out()), new JCSPNetworkServiceOut(wish.out(), "5563"), new JCSPNetworkServiceOut(delivery.out(), "5564"), new JCSPNetworkServiceIn(printOut.in(), "5565") }; new Parallel(procs).run(); } }

WishList.java
1 2 3 4 5 6 7 8 9 10 11 package WishListProcess; import Util.Data; import org.jcsp.lang.*; import java.util.ArrayList; public class WishList implements CSProcess { AltingChannelInput wishIn;

MAINTENANCE AT THE NORTH POLE


12 13 14 15 16 17 out){ 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 } AltingChannelInput delivery; ChannelOutput out; Alternative alt; ArrayList<Data> wishList = new ArrayList<Data>();

96

public WishList(AltingChannelInput wishIn, AltingChannelInput delivery, ChannelOutput this.wishIn = wishIn; this.delivery = delivery; Guard[] guard = {delivery, wishIn}; alt = new Alternative(guard); this.out = out; } public void run(){ while(true){ switch (alt.priSelect()){ case 0 : delivery.read(); String output = "["; System.out.println("Gifts for: "); for(Data d : wishList){ output += "\"" + d.getAuthor() + " : " + d.getMessage() + "\","; } wishList.clear(); output = output.substring(0,output.length() - 1) + "]"; System.out.println(output); Data data = new Data("all", output); data.setType("Delivery"); out.write(data); break; case 1 : Data msg = (Data)wishIn.read(); if(msg.getType().equals("wishlist")){ wishList.add(msg); System.out.println(msg.getMessage()); } break; } } }

Server Package StartServer.java


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package Server; import import import import import import Util.JCSPNetworkServiceIn; Util.JCSPNetworkServiceOut; org.jcsp.lang.Any2OneChannel; org.jcsp.lang.CSProcess; org.jcsp.lang.Channel; org.jcsp.lang.Parallel;

public class StartServer { public static void main(String[] args){ NettoServer ns = new NettoServer(); Any2OneChannel printOut = Channel.any2one(); CSProcess[] procs = { new BroadcastOutMain(printOut.in()), new JCSPNetworkServiceIn(NorthPole.GetChannel.getInput(), "5563"), new JCSPNetworkServiceOut(printOut.out(), "5565"), new JCSPNetworkServiceOut(printOut.out(), "5566") }; new Parallel(procs).run(); }

MAINTENANCE AT THE NORTH POLE


25 }

97

NorthPole.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package Server; import import import import import import import import import import Util.Data; org.atmosphere.config.service.Get; org.atmosphere.config.service.ManagedService; org.atmosphere.config.service.Message; org.atmosphere.cpr.*; org.codehaus.jackson.map.ObjectMapper; org.jcsp.lang.AltingChannelInput; org.jcsp.lang.Any2OneChannel; org.jcsp.lang.Channel; org.jcsp.lang.ChannelOutput;

import java.io.IOException; @ManagedService(path = "/northpole") public class NorthPole { private final ObjectMapper mapper = new ObjectMapper(); Broadcaster b = BroadcasterFactory.getDefault().get("/"); @Get public void onOpen(final AtmosphereResource r) { b.addAtmosphereResource(r); } @Message public String onMessage(String message) throws IOException { Data data = mapper.readValue(message, Data.class); GetChannel.getOutput().write(data); return mapper.writeValueAsString(data); } public final static class GetChannel{ public static Any2OneChannel a2o = Channel.any2one(); public static AltingChannelInput getInput(){ return a2o.in(); } public static ChannelOutput getOutput(){ return a2o.out(); } } }

BroadcastOutMain.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package Server; import import import import import import import Util.Data; org.atmosphere.cpr.Broadcaster; org.atmosphere.cpr.BroadcasterFactory; org.codehaus.jackson.map.ObjectMapper; org.jcsp.lang.CSProcess; org.jcsp.lang.ChannelInput; java.util.concurrent.Future;

public class BroadcastOutMain implements CSProcess { final ChannelInput in; Broadcaster b; public BroadcastOutMain(ChannelInput in) { this.b = BroadcasterFactory.getDefault().lookup("/"); this.in = in; }

MAINTENANCE AT THE NORTH POLE


20 private final ObjectMapper mapper = new ObjectMapper(); 21 public void run() { 22 while (true) { 23 Data data = (Data)in.read(); 24 Future br = b.broadcast("{\"message\": " + wrapInQuotes(data) + "," + 25 "\"who\":\""+data.getWho()+"\","+ 26 "\"type\":\"northPole\"}"); 27 28 } 29 } 30 private String wrapInQuotes(Data data){ 31 return ("Delivery".equals(data.getType()) ? data.getMessage() : "\"" data.getMessage()+ "\" " ); 32 } 33 }

98

Util Package JCSPNetworkServiceIn.java


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package Util; import org.jcsp.lang.CSProcess; import org.jcsp.lang.ChannelInput; import org.jeromq.ZMQ; public class JCSPNetworkServiceIn implements CSProcess { private final ChannelInput in; String port; public JCSPNetworkServiceIn(ChannelInput in, String port){ this.in = in; this.port = port; } @Override public void run() { ZMQ.Context context = ZMQ.context(1); ZMQ.Socket push = context.socket(ZMQ.PUSH); push.connect("tcp://localhost:" + port); while(!Thread.currentThread().isInterrupted()){ Data d = (Data)in.read(); push.send(d.toByteArray()); } push.close(); context.term (); } }

JCSPNetworkServiceOut.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package Util; import org.jcsp.lang.CSProcess; import org.jcsp.lang.ChannelOutput; import org.jeromq.ZMQ; public class JCSPNetworkServiceOut implements CSProcess { private final ChannelOutput out; String port; public JCSPNetworkServiceOut(ChannelOutput out, String port){ this.port = port; this.out = out; } @Override public void run() { ZMQ.Context context = ZMQ.context(1);

MAINTENANCE AT THE NORTH POLE


19 20 21 22 23 24 25 26 27 28 ZMQ.Socket subscriber = context.socket(ZMQ.PULL); subscriber.bind("tcp://*:"+port); while (!Thread.currentThread ().isInterrupted ()) { Data contents = Data.buildFromBytes(subscriber.recv()); out.write(contents); } subscriber.close(); context.term (); } }

99

MAINTENANCE AT THE NORTH POLE Akka Version AkkaNorthPole Package NorthPole.java

100

1 package AkkaNorthPole.Main; 2 3 import AkkaNorthPole.Actors.*; 4 import AkkaNorthPole.Messages.Msg; 5 import AkkaNorthPole.Messages.NorthPoleMsg; 6 import Util.OutputActor; 7 import akka.actor.ActorRef; 8 import akka.actor.ActorSystem; 9 import akka.actor.Props; 10 11 import java.io.IOException; 12 import java.util.ArrayList; 13 import java.util.List; 14 15 class NorthPole{ 16 17 enum name{ Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donder, Blitzen, Ruldolph } 18 19 public static void main(String[] args) throws IOException { 20 List<ActorRef> elves = new ArrayList<ActorRef>(); 21 List<ActorRef> reindeer = new ArrayList<ActorRef>(); 22 23 ActorSystem system = ActorSystem.create("NorthPole"); 24 ActorRef wishList = system.actorOf(Props.create(OutputActor.class, "5564")); 25 ActorRef santa = system.actorOf(Props.create(Santa.class, "Santa", wishList)); 26 ActorRef waitingRoom = system.actorOf(Props.create(WaitingRoom.class, "WaitingRoom", santa)); 27 santa.tell(new Msg(NorthPoleMsg.WaitingRoom), waitingRoom); 28 29 for (int i = 1; i <= 10; i++){ 30 elves.add(system.actorOf(Props.create(Elf.class, "Elf" + String.valueOf(i), waitingRoom))); 31 } 32 for (name r : name.values()){ 33 reindeer.add(system.actorOf(Props.create(Reindeer.class, r.toString(), waitingRoom))); 34 } 35 ActorRef mrsClaus = system.actorOf(Props.create(MrsClaus.class, santa)); 36 } 37 }

Msg.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package AkkaNorthPole.Messages; import akka.actor.ActorRef; import java.util.List; public class Msg { public final NorthPoleMsg nPMsg; public final String group; public final List<ActorRef> who; public Msg (NorthPoleMsg nPMsg){ this(nPMsg,"",null); } public Msg (NorthPoleMsg nPMsg, String group){ this(nPMsg,group,null); } public Msg(NorthPoleMsg nPMsg, String group, List<ActorRef> who){ this.nPMsg = nPMsg; this.group = group;

MAINTENANCE AT THE NORTH POLE


22 23 24 this.who = who; } }

101

NorthPoleMsg.java
1 2 3 4 5 6 7 8 9 package AkkaNorthPole.Messages; public enum NorthPoleMsg { Cookies, Back, Wait, Allowed, Full, Last, WakeUp, ComeIn, Consult, GoodBye, Hitch, Deliver, Unhitch, Dismiss, Done, GetToWork, WaitingRoom, GoOnVacation }

State.java
1 2 3 4 5 package AkkaNorthPole.Actors; public interface State { }

NorthPoleActor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package AkkaNorthPole.Actors; import import import import import import import import AkkaNorthPole.Messages.Msg; AkkaNorthPole.Messages.NorthPoleMsg; Util.Data; Util.OutputActor; akka.actor.ActorRef; akka.actor.Props; akka.actor.UntypedActor; scala.concurrent.duration.Duration;

import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; public abstract class NorthPoleActor extends UntypedActor{ final String name; private State state; Random randomGenerator = new Random(); ActorRef output; public static Props mkProps(String name) { return Props.create(NorthPoleActor.class, name); } public NorthPoleActor (String name) { this.name = name; System.out.println(name + " is starting at " + this.self().path().toString()); output = getContext().actorOf(Props.create(OutputActor.class, "5563")); } protected void setState(State s) { if (state != s) { state = s; } } protected State getState(){ return state; } public void log(String s){

MAINTENANCE AT THE NORTH POLE

102

45 System.out.println(name + ": " + s); 46 output.tell(new Data(name, s), getSelf()); 47 } 48 49 protected void reQueue(NorthPoleMsg msg){ 50 reQueue(new Msg(msg), self(), randomGenerator.nextInt(100) * 100, self()); 51 } 52 53 protected void batchSend(List<ActorRef> who, Msg what){ 54 for (ActorRef a : who){ 55 a.tell(what, getSelf()); 56 } 57 } 58 protected void reQueue(final Msg msg, final ActorRef sender, int time, final ActorRef reciever) { 59 context().system().scheduler().scheduleOnce(Duration.create(time, TimeUnit.MILLISECONDS), 60 new Runnable() { 61 @Override 62 public void run() { 63 reciever.tell(msg, sender); 64 } 65 }, context().system().dispatcher()); 66 } 67 68 @Override 69 public void onReceive(Object message) throws Exception {} 70 71 }

Elf.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package AkkaNorthPole.Actors; import AkkaNorthPole.Messages.Msg; import AkkaNorthPole.Messages.NorthPoleMsg; import akka.actor.ActorRef; public class Elf extends NorthPoleActor{ private ActorRef waitingRoom; public Elf(String name) { super(name); setState(ElfState.onVacation); } public Elf(String name, ActorRef waitingRoom){ this(name); this.waitingRoom = waitingRoom; reQueue(NorthPoleMsg.Back); } enum ElfState implements State { onVacation, working, inWaitingRoom, withSanta } @Override public void onReceive(Object message) throws Exception { Msg msg = (Msg)message; Thread.sleep(randomGenerator.nextInt(100) * 20); switch(msg.nPMsg){ case Back: log("Working"); waitingRoom.tell(new Msg(NorthPoleMsg.Wait, "Elves"), getSelf()); setState(ElfState.working); break; case Allowed: log ("In the waiting room"); setState(ElfState.inWaitingRoom); break; case Full: log("Waiting room is full");

MAINTENANCE AT THE NORTH POLE


41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 getSender()); 68 69 70 getSender()); 71 72 73 74 75 } 76 } 77 }

103

reQueue(NorthPoleMsg.Back); break; case Last: log("Going to wake santa"); sender().tell(new Msg(NorthPoleMsg.WakeUp, msg.group, msg.who), getSelf()); break; case ComeIn: log("Entering Santa's house"); setState(ElfState.withSanta); sender().tell(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf()); break; case Consult: log("Consulting with Santa"); sender().tell(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf()); break; case GoodBye: log("Leaving santa's"); sender().tell(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf()); break; case GetToWork: log("Going to work"); setState(ElfState.onVacation); reQueue(NorthPoleMsg.Back); break; case Wait: log("Waiting"); reQueue(new Msg(NorthPoleMsg.WakeUp, msg.group, msg.who), getSelf(), 100, break; case Cookies: reQueue(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf(), 100, break; default: break;

Reindeer.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package AkkaNorthPole.Actors; import AkkaNorthPole.Messages.Msg; import AkkaNorthPole.Messages.NorthPoleMsg; import akka.actor.ActorRef; public class Reindeer extends NorthPoleActor{ private final ActorRef waitingRoom; enum ReindeerState implements State { onVacation, backFromVacation, inWaitingRoom, hitched, deliveringToys } public Reindeer(String name) { this(name,null); } public Reindeer(String name, ActorRef waitingRoom) { super(name); this.waitingRoom = waitingRoom; setState(ReindeerState.onVacation); reQueue(NorthPoleMsg.Back); } @Override public void onReceive(Object message) throws Exception { Msg msg = (Msg)message;

MAINTENANCE AT THE NORTH POLE

104

31 Thread.sleep(randomGenerator.nextInt(100) * 20); 32 switch(msg.nPMsg){ 33 case Back: 34 log("Back from vacation"); 35 waitingRoom.tell(new Msg(NorthPoleMsg.Wait, "Reindeer"), getSelf()); 36 setState(ReindeerState.backFromVacation); 37 break; 38 case Allowed: 39 log ("In the waiting room"); 40 setState(ReindeerState.inWaitingRoom); 41 break; 42 case Full: 43 log("Waiting room is full"); 44 reQueue(NorthPoleMsg.Back); 45 break; 46 case Last: 47 log("Going to wake santa"); 48 sender().tell(new Msg(NorthPoleMsg.WakeUp, msg.group, msg.who), getSelf()); 49 break; 50 case Hitch: 51 log("Getting Hitched"); 52 setState(ReindeerState.hitched); 53 sender().tell(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf()); 54 break; 55 case Deliver: 56 log("Delivering Toys"); 57 setState(ReindeerState.deliveringToys); 58 sender().tell(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf()); 59 break; 60 case Unhitch: 61 log("Getting unhitched"); 62 sender().tell(new Msg(NorthPoleMsg.Done, msg.group, msg.who), getSelf()); 63 break; 64 case GoOnVacation: 65 log("Going on Vacation"); 66 setState(ReindeerState.onVacation); 67 reQueue(NorthPoleMsg.Back); 68 break; 69 case Wait: 70 log("Waiting"); 71 reQueue(new Msg(NorthPoleMsg.WakeUp, msg.group, msg.who), getSelf(), 100, getSender()); 72 break; 73 default: 74 break; 75 } 76 } 77 }

Santa.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package AkkaNorthPole.Actors; import import import import AkkaNorthPole.Messages.Msg; AkkaNorthPole.Messages.NorthPoleMsg; Util.Data; akka.actor.ActorRef;

import java.util.HashMap; import java.util.List; public class Santa extends NorthPoleActor{ enum santaState implements State {awake, asleep, welcomingElves, consultingWithElves, dismissingElves, hitchingReindeer, deliveringToys, dismissingReindeer, eatingCookies} int wait = 0; private ActorRef waitingRoom; private ActorRef wishList; private HashMap<String, Msg> visitorQueue = new HashMap<String, Msg>();

MAINTENANCE AT THE NORTH POLE

105

22 public Santa(String name, ActorRef wishList) { 23 super(name); 24 this.wishList = wishList; 25 setState(santaState.asleep); 26 log("Sleeping"); 27 } 28 @Override 29 public void onReceive(Object message) throws Exception { 30 Msg msg = (Msg)message; 31 switch (msg.nPMsg) { 32 case WakeUp : 33 visitorQueue.put(msg.group, msg); 34 if(getState().equals(santaState.asleep)) { 35 if(visitorQueue.containsKey("Reindeer")) { 36 if(msg.group.equals("Elves")){ 37 getSender().tell(new Msg(NorthPoleMsg.Wait, msg.group, msg.who), getSelf()); 38 } 39 handleVisitors(visitorQueue.get("Reindeer")); 40 visitorQueue.remove("Reindeer"); 41 } 42 else { 43 handleVisitors(visitorQueue.get("Elves")); 44 visitorQueue.remove("Elves"); 45 } 46 } 47 else { 48 getSender().tell(new Msg(NorthPoleMsg.Wait, msg.group, msg.who), getSelf()); 49 } 50 break; 51 case Done : 52 if (getState().equals(santaState.eatingCookies)){ 53 getSender().tell(new Msg(NorthPoleMsg.Cookies, msg.group, msg.who), getSelf()); 54 } 55 else if (wait > 1) { 56 wait--; 57 } 58 else { 59 switch((santaState)getState()){ 60 case welcomingElves : 61 log("Welcoming elves"); 62 setState(santaState.consultingWithElves); 63 doAction(msg.who, new Msg(NorthPoleMsg.Consult, msg.group, msg.who)); 64 break; 65 case consultingWithElves : 66 log("Consulting with elves"); 67 setState(santaState.dismissingElves); 68 doAction(msg.who, new Msg(NorthPoleMsg.GoodBye, msg.group, msg.who)); 69 break; 70 case dismissingElves : 71 log("Sleeping"); 72 setState(santaState.asleep); 73 waitingRoom.tell(new Msg(NorthPoleMsg.Dismiss, msg.group, msg.who),getSelf()); 74 break; 75 case hitchingReindeer : 76 log("Harnessing reindeer"); 77 setState(santaState.deliveringToys); 78 wishList.tell(new Data("wishlist","Deliver"), null); 79 doAction(msg.who, new Msg(NorthPoleMsg.Deliver, msg.group, msg.who)); 80 break; 81 case deliveringToys : 82 log("Delivering Toys"); 83 setState(santaState.dismissingReindeer); 84 doAction(msg.who, new Msg(NorthPoleMsg.Unhitch, msg.group, msg.who)); 85 break; 86 case dismissingReindeer :

MAINTENANCE AT THE NORTH POLE

106

87 log("Unharnessing reindeer"); 88 log("Sleeping"); 89 setState(santaState.asleep); 90 waitingRoom.tell(new Msg(NorthPoleMsg.Dismiss, msg.group, msg.who),getSelf()); 91 break; 92 } 93 } 94 break; 95 case WaitingRoom : 96 waitingRoom = getSender(); 97 break; 98 case Cookies: 99 if(getState().equals(santaState.welcomingElves) || getState().equals(santaState.consultingWithElves) || 100 getState().equals(santaState.dismissingElves)){ 101 State savedState = getState(); 102 setState(santaState.eatingCookies); 103 log("Eating Cookies with Mrs. Claus"); 104 reQueue(new Msg(NorthPoleMsg.Done), getSelf(), 200, getSender()); 105 setState(savedState); 106 } 107 else{ 108 getSender().tell(new Msg(NorthPoleMsg.Wait), getSelf()); 109 } 110 break; 111 default: 112 break; 113 } 114 } 115 116 private void doAction(List<ActorRef> who, Msg what){ 117 wait = who.size(); 118 batchSend(who,what); 119 } 120 121 private void handleVisitors(Msg msg){ 122 setState(santaState.awake); 123 log("Waking up"); 124 if(msg.group.equals("Elves")){ 125 setState(santaState.welcomingElves); 126 doAction(msg.who, new Msg(NorthPoleMsg.ComeIn, msg.group, msg.who)); 127 } 128 else if(msg.group.equals("Reindeer")){ 129 setState(santaState.hitchingReindeer); 130 doAction(msg.who, new Msg(NorthPoleMsg.Hitch, msg.group, msg.who)); 131 } 132 } 133 }

MrsClaus.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package AkkaNorthPole.Actors; import import import import AkkaNorthPole.Messages.Msg; AkkaNorthPole.Messages.NorthPoleMsg; akka.actor.ActorRef; akka.actor.Props;

public class MrsClaus extends NorthPoleActor{ public static Props mkProps(String name) { return Props.create(NorthPoleActor.class, name); } private final ActorRef santa; public MrsClaus(ActorRef santa){ super("MrsClaus"); this.santa = santa; reQueue(new Msg(NorthPoleMsg.Back), getSelf(), 1000, getSelf()); }

MAINTENANCE AT THE NORTH POLE


21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

107

@Override public void onReceive(Object message) throws Exception{ Msg msg = (AkkaNorthPole.Messages.Msg)message; switch (msg.nPMsg){ case Back: reQueue(new Msg(NorthPoleMsg.Cookies), getSelf(), 2000, santa); log("Going to Santa's"); break; case Wait: log("Santa is Busy...Waiting"); reQueue(new Msg(NorthPoleMsg.Cookies), getSelf(), 2000, santa); break; case Done: log("Going back home"); reQueue(new Msg(NorthPoleMsg.Back), getSelf(), 2000, getSelf()); break; } } }

WaitingRoom.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package AkkaNorthPole.Actors; import AkkaNorthPole.Messages.Msg; import AkkaNorthPole.Messages.NorthPoleMsg; import akka.actor.ActorRef; import java.util.ArrayList; import java.util.List; public class WaitingRoom extends NorthPoleActor{ private List<ActorRef> elves = new ArrayList(); private List<ActorRef> reindeer = new ArrayList(); waitingRoomState reindeerWaiting; waitingRoomState elfWaiting; private ActorRef santa; enum waitingRoomState implements State {full, notFull} public WaitingRoom(String name) { super(name); } public WaitingRoom(String name, ActorRef santa){ this(name); this.santa = santa; reindeerWaiting = waitingRoomState.notFull; elfWaiting = waitingRoomState.notFull; } @Override public void onReceive(Object message) throws Exception { Thread.sleep(randomGenerator.nextInt(100) * 2); Msg msg = (Msg)message; switch (msg.nPMsg) { case Wait : if(msg.group.equals("Elves")) queue(elves, msg.group, 3); else if(msg.group.equals("Reindeer")) queue(reindeer, msg.group, 9); break; case Dismiss : if(msg.group.equals("Elves")) { batchSend(msg.who, new Msg(NorthPoleMsg.GetToWork)); elves.clear(); elfWaiting = waitingRoomState.notFull; } else if(msg.group.equals("Reindeer")) { batchSend(msg.who, new Msg(NorthPoleMsg.GoOnVacation)); reindeer.clear();

MAINTENANCE AT THE NORTH POLE


49 reindeerWaiting = waitingRoomState.notFull; 50 } 51 default: 52 } 53 } 54 private void queue(List<ActorRef> who, String group, int size){ 55 if((group.equals("Elves") && elfWaiting.equals(waitingRoomState.notFull)) || 56 (group.equals("Reindeer") reindeerWaiting.equals(waitingRoomState.notFull))){ 57 getSender().tell(new Msg(NorthPoleMsg.Allowed), santa); 58 who.add(sender()); 59 if(who.size() == size){ 60 if(group.equals("Elves")) 61 elfWaiting = waitingRoomState.full; 62 else if(group.equals("Reindeer")) 63 reindeerWaiting = waitingRoomState.full; 64 getSender().tell(new Msg(NorthPoleMsg.Last, group, who), santa); 65 } 66 } 67 else{ 68 getSender().tell(new Msg(NorthPoleMsg.Full), getSelf()); 69 } 70 } 71 }

108

&&

WishList Package StartWishList.java


1 2 3 4 5 6 7 8 9 10 11 12 13 package WishList; import akka.actor.ActorSystem; import akka.actor.Props; public class StartWishList { public static void main(String[] args){ ActorSystem system = ActorSystem.create("Server"); system.actorOf(Props.create(WishList.class)); } }

WishList.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package WishList; import import import import import import import Util.Data; Util.InputActor; Util.OutputActor; akka.actor.ActorRef; akka.actor.Props; akka.actor.UntypedActor; java.util.concurrent.CopyOnWriteArrayList;

public class WishList extends UntypedActor { private CopyOnWriteArrayList<Data> wishList = new CopyOnWriteArrayList<Data>(); private ActorRef delivery; private ActorRef wish; private ActorRef out; WishList(){ delivery = getContext().actorOf(Props.create(InputActor.class, "5564", getSelf())); wish = getContext().actorOf(Props.create(InputActor.class, "5565", getSelf())); out = getContext().actorOf(Props.create(OutputActor.class, "5563")); delivery.tell("Start", getSelf()); wish.tell("Start", getSelf()); } @Override

MAINTENANCE AT THE NORTH POLE


26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public void onReceive(Object o) throws Exception { if(o instanceof Data){ Data d = (Data)o; if(d.getMessage().equals("Deliver")){ deliverGifts(); } else{ addToWishList(d); } } } private void deliverGifts(){ String output = "["; System.out.println("Gifts for: "); for(Data d : wishList){ output += "\"" + d.getAuthor() + " : " + d.getMessage() + "\","; } wishList.clear(); output = output.substring(0,output.length() - 1) + "]"; System.out.println(output); Data data = new Data("all", output); data.setType("Delivery"); out.tell(data,getSelf()); } private void addToWishList(Data msg){ if(msg.getType().equals("wishlist")){ wishList.add(msg); System.out.println(msg.getMessage()); } } }

109

Server Package StartServer.java


1 package Server; 2 3 import Util.OutputActor; 4 import akka.actor.ActorSystem; 5 import akka.actor.Props; 6 7 public class StartServer { 8 9 public static void main(String[] args){ 10 NettoServer ns = new NettoServer(); 11 ActorSystem system = ActorSystem.create("Server"); 12 system.actorOf(Props.create(BroadcastOutMain.class)); 13 NorthPole.InjectWishList.wishList = system.actorOf(Props.create(OutputActor.class, "5565")); 14 } 15 }

NorthPole.java
1 2 3 4 5 6 7 8 9 10 11 12 package Server; import import import import import import import import import import akka.actor.ActorRef; org.atmosphere.config.service.Get; org.atmosphere.config.service.ManagedService; org.atmosphere.config.service.Message; org.atmosphere.cpr.AtmosphereResource; org.atmosphere.cpr.Broadcaster; org.atmosphere.cpr.BroadcasterFactory; org.codehaus.jackson.map.ObjectMapper; java.io.IOException; Util.*;

MAINTENANCE AT THE NORTH POLE


13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

110

@ManagedService(path = "/northpole") public class NorthPole { private final ObjectMapper mapper = new ObjectMapper(); Broadcaster b = BroadcasterFactory.getDefault().get("/"); @Get public void onOpen(final AtmosphereResource r) { b.addAtmosphereResource(r); } @Message public String onMessage(String message) throws IOException { Data d = mapper.readValue(message, Data.class); InjectWishList.wishList.tell(d, null); return mapper.writeValueAsString(d); } public static class InjectWishList{ public static ActorRef wishList; } }

BroadcastOutMain.java
1 package Server; 2 3 import akka.actor.ActorRef; 4 import akka.actor.Props; 5 import akka.actor.UntypedActor; 6 import org.atmosphere.cpr.Broadcaster; 7 import org.atmosphere.cpr.BroadcasterFactory; 8 import Util.*; 9 10 import java.util.concurrent.Future; 11 12 public class BroadcastOutMain extends UntypedActor { 13 14 Broadcaster b; 15 private ActorRef input; 16 17 public BroadcastOutMain() { 18 this.b = BroadcasterFactory.getDefault().lookup("/"); 19 this.input = getContext().actorOf(Props.create(InputActor.class, getSelf())); 20 input.tell("Start", getSelf()); 21 } 22 23 @Override 24 public void onReceive(Object message) throws Exception { 25 Data msg = (Data)message; 26 Future br = b.broadcast("{\"message\": " + wrapInQuotes(msg) + "," + 27 "\"who\":\""+msg.getWho()+"\","+ 28 "\"type\":\"northPole\"}"); 29 } 30 31 private String wrapInQuotes(Data data){ 32 return ("Delivery".equals(data.getType()) ? data.getMessage() : data.getMessage()+ "\" " ); 33 } 34 }

"5563",

"\""

Util Package InputActor.java


1 2 3 package Util; import akka.actor.ActorRef;

MAINTENANCE AT THE NORTH POLE


4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import akka.actor.UntypedActor; import org.jeromq.ZMQ; public class InputActor extends UntypedActor{ String port; ActorRef responder; ZMQ.Context context; ZMQ.Socket pull; public InputActor(String port, ActorRef responder){ this.port = port; this.responder = responder; context = ZMQ.context(1); pull = context.socket(ZMQ.PULL); pull.bind("tcp://*:" + port); } private void run(){ while (true) { Data contents = Data.buildFromBytes(pull.recv()); responder.tell(contents, getSelf()); } } private void stop(){ pull.close(); context.term(); } @Override public void onReceive(Object o) throws Exception { if(o instanceof String){ if (o.equals("Start")){ run(); } else if(o.equals("End")){ stop(); } } } }

111

OutputActor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package Util; import akka.actor.UntypedActor; import org.jeromq.ZMQ; public class OutputActor extends UntypedActor{ private ZMQ.Socket push; private ZMQ.Context context; final String port; public OutputActor(String port){ this.port = port; context = ZMQ.context(1); push = context.socket(ZMQ.PUSH); push.connect("tcp://localhost:" + port); } @Override public void onReceive(Object o) throws Exception { if(o instanceof Data){ Data data = (Data)o; push.send(data.toByteArray()); } } }

MAINTENANCE AT THE NORTH POLE References Agha, G., & Hewitt, C. (1985). Concurrent programming using actors: Exploiting large-scale parallelism (pp. 1941). Retrieved from http://www.springerlink.com/index/y1wl7q3342006720.pdf

112

Al Qutaish, R. E., & Abran, A. (2005). An Analysis of the Design and Definitions of Halsteads Metrics. In 15th Int. Workshop on Software Measurement (IWSM2005). Shaker-Verlag (pp. 337352). Retrieved from http://s3.amazonaws.com/publicationslist.org/data/a.abran/ref-2084/905.pdf Bailey, C. T., & Dingee, W. L. (1981). A Software Study Using Halstead Metrics. In Proceedings of the 1981 ACM Workshop/Symposium on Measurement and Evaluation of Software Quality (pp. 189197). New York, NY, USA: ACM. doi:10.1145/800003.807928 Belapurkar, A. (2005, June 21). CSP for Java programmers, Part 1. CT316. Retrieved May 22, 2013, from http://www.ibm.com/developerworks/java/library/j-csp1/index.html Berns, G. M. (1984). Assessing software maintainability. Communications of the ACM, 27(1), 1423. Ben-Ari, M. (1998). How to solve the Santa Claus problem. Concurrency: Practice and Experience, 10(6), 485496. doi:10.1002/(SICI)1096-9128(199805)10:6<485::AIDCPE329>3.0.CO;2-2 Benton, N. (2003). Jingle bells: Solving the Santa Claus Problem in Polyphonic C#. Microsoft Research. Retrieved from http://research.microsoft.com/enus/um/people/nick/polyphony/santa.pdf

MAINTENANCE AT THE NORTH POLE Betin-Can, A., & Bultan, T. (2004). Verifiable concurrent programming using concurrency

113

controllers (pp. 248 257). Presented at the 19th International Conference on Automated Software Engineering, 2004. Proceedings. doi:10.1109/ASE.2004.1342742 Blackburn, J., Scudder, G., & Van Wassenhove, L. N. (2000). Concurrent software development. Commun. ACM, 43(11es). doi:10.1145/352515.352519 Boehm, B. W., Brown, J. R., & Lipow, M. (1976). Quantitative evaluation of software quality. In Proceedings of the 2nd international conference on Software engineering (pp. 592605). Retrieved from http://dl.acm.org/citation.cfm?id=807736 Boner, J. (2012). Above the Clouds: Introducing Akka. Retrieved from http://www.youtube.com/watch?v=UY3fuHebRMI&feature=youtube_gdata_player Bouwers, E., Correia, J. P., Deursen, A. van, & Visser, J. (2011). Quantifying the Analyzability of Software Architectures (pp. 8392). Washington, DC, USA: IEEE Computer Society. doi:10.1109/WICSA.2011.20 Broy, M., Deissenboeck, F., & Pizka, M. (2006). Demystifying maintainability (pp. 2126). New York, NY, USA: ACM. doi:10.1145/1137702.1137708 Chidamber, S. R., & Kemerer, C. F. (1994). A metrics suite for object oriented design. IEEE Transactions on Software Engineering, 20(6), 476493. doi:10.1109/32.295895 Codehaus. (2006). 4 Groovy CSP 1.0.0. Retrieved June 19, 2013, from http://www.gpars.org/1.0.0/guide/guide/GroovyCSP.html Coleman, D., Ash, D., Lowther, B., & Oman, P. (1994). Using metrics to evaluate software system maintainability. Computer, 27(8), 4449. Corra, F. (2009). Actors in a new highly parallel world (pp. 2124). New York, NY, USA: ACM. doi:10.1145/1527033.1527041

MAINTENANCE AT THE NORTH POLE Cox, R. (2013, May 22). Bell Labs and CSP Threads. Retrieved May 22, 2013, from http://swtch.com/~rsc/thread/ Curtis, B., Sheppard, S. B., Milliman, P., Borst, M. A., & Love, T. (1979). Measuring the Psychological Complexity of Software Maintenance Tasks with the Halstead and McCabe Metrics. IEEE Transactions on Software Engineering, SE-5(2), 96104. doi:10.1109/TSE.1979.234165

114

De Souza, L. B. L., & Maia, M. D. A. (2013). Do Software Categories Impact Coupling Metrics? In Proceedings of the 10th Working Conference on Mining Software Repositories (pp. 217220). Piscataway, NJ, USA: IEEE Press. Retrieved from http://dl.acm.org.dml.regis.edu/citation.cfm?id=2487085.2487128 Downey, A. B. (2005). The Little Book of Semaphores. Green Tea Press. Elshoff, J. L., & Marcotty, M. (1978). On the Use of the Cyclomatic Number to Measure Program Complexity. SIGPLAN Notes, 13(12), 2940. doi:10.1145/954587.954590 Erb, B. (2013, January 20). Concurrent Programming for Scalable Web Architectures (PhD. Dissertation). University of Ulm. Retrieved from http://berb.github.com/diplomathesis/index.html Fowler, M. (2002). Patterns of Enterprise Application Architecture (1st ed.). Addison-Wesley Professional. Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software (1st ed.). Addison-Wesley Professional. Ghosh, D., Sheehy, J., Thorup, K. K., & Vinoski, S. (2011). Programming language impact on the development of distributed systems. Journal of Internet Services and Applications, 3(1), 2330. doi:10.1007/s13174-011-0042-y

MAINTENANCE AT THE NORTH POLE

115

Gill, G. K., & Kemerer, C. F. (1991). Cyclomatic complexity density and software maintenance productivity. IEEE Transactions on Software Engineering, 17(12), 12841288. doi:10.1109/32.106988 Glass, R. L. (2003). Facts and Fallacies of Software Engineering. Addison-Wesley Professional. Goetz, B. (2004). A First Look at JSR 166: Concurrency Utilities | Java.net. Retrieved May 23, 2013, from https://today.java.net/pub/a/today/2004/03/01/jsr166.html Goetz, B., Peierls, T., Bloch, J., Bowbeer, J., Holmes, D., & Lea, D. (2006). Java Concurrency in Practice (1st ed.). Addison-Wesley Professional. Graham, P. (2002). Revenge of the Nerds. Grogono, P., & Shearing, B. (2008). Concurrent software engineering: preparing for paradigm shift (pp. 99108). New York, NY, USA: ACM. doi:10.1145/1370256.1370270 Gupta, M. (2012). Akka Essentials. Packt Publishing Ltd. Haller, P. (2012). On the integration of the actor model in mainstream technologies: the scala perspective (pp. 16). New York, NY, USA: ACM. doi:10.1145/2414639.2414641 Halstead, M. H. (1977). Elements of software science. New York: Elsevier. Harrison, W., Magel, K., Kluczny, R., & DeKock, A. (1982). Applying software complexity metrics to program maintenance. Computer, 15(9), 6579. Hewitt, C., Bishop, P., & Steiger, R. (1973). A universal modular ACTOR formalism for artificial intelligence (pp. 235245). San Francisco, CA, USA: Morgan Kaufmann Publishers Inc. Retrieved from http://dl.acm.org/citation.cfm?id=1624775.1624804 Hoare, C. A. R. (Ed.). (1985). Communicating Sequential Processes. Prentice-Hall. Hoare, Charles Antony Richard. (1978). Communicating sequential processes. Communications of the ACM, 21(8), 666677.

MAINTENANCE AT THE NORTH POLE

116

Humble, J., & Farley, D. (2011). Continuous delivery: reliable software releases through build, test, and deployment automation. Upper Saddle River, NJ: Addison-Wesley. Hurt, J., & Pedersen, J. B. (2008). Solving the Santa Claus problem: A comparison of various concurrent programming techniques. Communicating Process Architectures. IEEE. (2004). SWEBOK Guide - Chapter 3. Retrieved from http://www.computer.org/portal/web/swebok/html/ch3#Ref18 ISO, I. (2011). IEC 25010: 2011: Systems and software engineeringSystems and software Quality Requirements and Evaluation (SQuaRE)System and software quality models. International Organization for Standardization. Jeet, K., Dhir, R., & Verma, H. (2012). A comparative study of bayesian and fuzzy approach to assess and predict maintainability of the software using activity-based quality model. SIGSOFT Software Engineering Notes, 37(3), 19. doi:10.1145/180921.2180935 Jenkov, J. (2013, May 23). Java Concurrency Tutorial. Retrieved May 23, 2013, from http://tutorials.jenkov.com/java-concurrency/index.html Jones, S. P. (2007). Beautiful concurrency. Beautiful Code: Leading Programmers Explain How They Think (Theory in Practice (OReilly)). OReilly Media, Inc, 385406. Kearney, J. P., Sedlmeyer, R. L., Thompson, W. B., Gray, M. A., & Adler, M. A. (1986). Software complexity measurement. Communications of the ACM, 29(11), 10441050. Karmani, R. K., Shali, A., & Agha, G. (2009). Actor frameworks for the JVM platform: a comparative analysis (pp. 1120). New York, NY, USA: ACM. doi:10.1145/1596655.1596658 Kaur, K., & Singh, H. (2011). Determination of Maintainability Index for Object Oriented Systems. SIGSOFT Software Engineering Notes, 36(2), 16. doi:10.1145/1943371.1943383

MAINTENANCE AT THE NORTH POLE

117

Kerridge, J. (2008). Santas Groovy Helper. In P. H. Welch, S. Stepney, F. A. . Polack, F. R. M. Barnes, A. A. McEwan, G. S. Stiles, A. T. Sampson (Eds.), Communicating Process Architectures 2008. Kerridge, J., Panayotopoulos, A., & Lismore, P. (2008). JCSPre: the robot edition to control LEGO NXT robots. Communicating Process Architectures, 66, 255270. Kulkarni, M., Pingali, K., Walter, B., Ramanarayanan, G., Bala, K., & Chew, L. P. (2007). Optimistic parallelism requires abstractions (Vol. 42, pp. 211222). Retrieved from http://dl.acm.org/citation.cfm?id=1250759 Lanza, M., & Marinescu, R. (2006). Object-oriented metrics in practice: using software metrics to characterize, evaluate, and improve the design of object-oriented systems. Springer. Lea, D. (2000). Concurrent programming in Java: design principles and patterns. Prentice Hall. Lehman, M. (1996). Laws of software evolution revisited. In Software process technology (pp. 108124). Springer. Retrieved from http://link.springer.com/chapter/10.1007/BFb0017737 Lehman, M., & Ramil, J. F. (2002). Software Evolution and Software Evolution Processes. Annals of Software Engineering, 14(1-4), 275309. doi:10.1023/A:1020557525901 Li, W., & Henry, S. (1993). Object-oriented metrics that predict maintainability. Journal of systems and software, 23(2), 111122. McCabe, T. J. (1976). A Complexity Measure. IEEE Transactions on Software Engineering, SE2(4), 308320. doi:10.1109/TSE.1976.233837 Mens, T., & Demeyer, S. (2008). Software evolution. New York; London: Springer. Menzies, T., Di Stefano, J. S., Chapman, M., & McGill, K. (2002). Metrics that matter. In Software Engineering Workshop, 2002. Proceedings. 27th Annual NASA Goddard/IEEE

MAINTENANCE AT THE NORTH POLE (pp. 5157). Retrieved from http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=1199449 Norvig, P. (1996). Design patterns in dynamic programming. Object World, 96(5). Papapetrou, P. P., & Campbell, G. A. (2013). Sonar in Action. Greenwich, Conn.; London: Manning

118

Rajan, H., Kautz, S. M., & Rowcliffe, W. (2010). Concurrency by modularity: design patterns, a case in point. SIGPLAN Not., 45(10), 790805. doi:10.1145/1932682.1869523 Riaz, M., Mendes, E., & Tempero, E. (2009). A systematic review of software maintainability prediction and metrics (pp. 367377). Washington, DC, USA: IEEE Computer Society. doi:10.1109/ESEM.2009.5314233 Ricken, M., & Cartwright, R. (2010). Test-first Java concurrency for the classroom. In Proceedings of the 41st ACM technical symposium on Computer science education (pp. 219223). Retrieved from http://dl.acm.org/citation.cfm?id=1734340 Roestenburg, R., Bakker, R., & Williams, R. (2013). Akka in Action. Manning Pubns Co. Roscoe, A. W. (1997). Theory and Practice of Concurrency. Prentice Hall. Sampson, A. T. (2010, October). Process-Oriented Patterns for Concurrent Software Engineering. University of Kent. Retrieved from http://offog.org/publications/atsthesis.pdf Schmidt, D. C., & Cranor, C. D. (1995). Half-Sync/Half-Async-An Architectural Pattern for Efficient and Well-structured Concurrent I/O. Retrieved from http://ukpmc.ac.uk/abstract/CIT/61269 Schmidt, D. C. & Lavender, R. G., (1995). Active object an object behavioral pattern for concurrent programming. Retrieved from http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.53.3579

MAINTENANCE AT THE NORTH POLE

119

Schmidt, D. C., Harrison, T., & Pryce, N. (1997). Thread-Specific StorageAn Object Behavioral Pattern for Accessing per-Thread State Efficiently. C++ Report, 9, 221. Sutter, H. (2005). The free lunch is over: A fundamental turn toward concurrency in software. Dr. Dobbs Journal, 30(3), 202210. Sutter, H., & Larus, J. (2005). Software and the Concurrency Revolution. Queue, 3(7), 5462. doi:10.1145/1095408.1095421 Trono, J. A. (1994). A new exercise in concurrency. ACM SIGCSE Bulletin, 26(3), 810. Typesafe. (2012). Akka. Retrieved May 22, 2013, from http://akka.io/ Van Solingen, R., Basili, V., Caldiera, G., & Rombach, H. D. (2002). Goal Question Metric (GQM) Approach. Encyclopedia of Software Engineering. Retrieved from http://onlinelibrary.wiley.com/doi/10.1002/0471028959.sof142/full Welch, P. H., & Austin, P. D. (2013, May 21). Overview (CSP for Java (JCSP) 1.1-rc4 API Specification (inc. Network)). Retrieved May 21, 2013, from http://www.cs.kent.ac.uk/projects/ofa/jcsp/jcsp-1.1-rc4/jcsp-doc/overview-summary.html Welch, P. H., & Pedersen, J. B. (2010). Santa Claus: Formal analysis of a process-oriented solution. ACM Trans. Program. Lang. Syst., 32(4), 14:114:37. doi:10.1145/1734206.1734211 Welch, P. P. (2002). Process Oriented Design for Java: Concurrency for All. In P. M. A. Sloot, A. G. Hoekstra, C. J. K. Tan, & J. J. Dongarra (Eds.), Computational Science ICCS 2002 (pp. 687687). Springer Berlin Heidelberg. Retrieved from http://link.springer.com/chapter/10.1007/3-540-46080-2_72

MAINTENANCE AT THE NORTH POLE Wiebusch, D., Fischbach, M., Latoschik, M. E., & Tramberend, H. (2012). Evaluating scala, actors, & ontologies for intelligent realtime interactive systems (pp. 153160). New York, NY, USA: ACM. doi:10.1145/2407336.2407365

120

Zheng, J., & Harper, K. E. (2010). Concurrency design patterns, software quality attributes and their tactics (pp. 4047). New York, NY, USA: ACM. doi:10.1145/1808954.1808964

Anda mungkin juga menyukai