bof2644 developing java ee 7 scala apps

69
Developing Java EE 7 Applications with Scala (CON2664) Demystifying the Object-Functional Peter Pilgrim Scala and Java EE Independent contractor @peter_pilgrim

Upload: peter-pilgrim

Post on 22-Apr-2015

1.481 views

Category:

Education


4 download

DESCRIPTION

Developing Java EE 7 Applications with Scala (CON2644) *Speakers: Peter Pilgrim* Abstract: 750 words Scala is an alternative JVM language with both object-oriented and functional programming paradigms. Scala development with the Java EE 7 platform is definitely possible and can be a pleasant experience. If you have uncertainty about how Scala can fit around the Java EE 7 platform, then this session aims to illustrate the huge benefit that Scala adoption can bring to the platform. Many other developers are taking advantage and the challenge of the JVM’s capability of being a vessel for multi-language programming. You no longer have to write every single project using Java, even if you like Lambdas experiences. For the developer and engineering terms that feeling a little braver than usual, Scala is attractive as it is strongly typed and lets you set the gauge on how object oriented or how functional you want to be. You will learn how to reuse the annotations and creating Scala plain object safely and concisely. This session will highlight and contrast the experience I had developing Scala solutions with Java EE, and there will be plenty of advice about using the functional programming features against the Java object oriented API.

TRANSCRIPT

Page 1: BOF2644 Developing Java EE 7 Scala apps

Developing Java EE 7 Applications with

Scala (CON2664) Demystifying the Object-Functional

Peter Pilgrim Scala and Java EE

Independent contractor

@peter_pilgrim  

Page 2: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Creative Commons 2.0 Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales (CC BY-NC-SA 2.0 UK) https://creativecommons.org/licenses/by-nc-sa/2.0/uk/

•  Share — copy and redistribute the material in

any medium or format •  Adapt — remix, transform, and build upon the

material •  The licensor cannot revoke these freedoms as

long as you follow the license terms.

2  

Page 3: BOF2644 Developing Java EE 7 Scala apps

Xenonique

About Me •  Scala and Java EE developer independent

contractor •  Digital transformation / e-commerce •  Java Champion •  Working on the JVM since 1998

3  

Page 4: BOF2644 Developing Java EE 7 Scala apps

Xenonique 4  

Java EE 7 Developer Handbook September  2013  Packt  Publishing    Digital Java EE 7 Web APPS December  2014  

Page 5: BOF2644 Developing Java EE 7 Scala apps

Xenonique 5  

Agenda •  Scala Technology •  Java EE 7 •  CDI •  JSF, Servlets •  JAX-RS, JMS

Page 6: BOF2644 Developing Java EE 7 Scala apps

Xenonique 6  

Page 7: BOF2644 Developing Java EE 7 Scala apps

Xenonique 7  

#1 Scala Object-functional Since 2003 Statically typed programming Scalable Language Inventor: Professor Martin Odersky, EPFL, Typesafe

Page 8: BOF2644 Developing Java EE 7 Scala apps

Xenonique 8  

#1 Scala Pattern Matching Case Classes Traits, Mix-ins, Collections Expressions, In-fix operators Functions, Closures, Control Abstractions Extension through Library functions

Page 9: BOF2644 Developing Java EE 7 Scala apps

Xenonique 9  

#1 Scala Gradle, Gradle, Gradle v2.0 Groovy assembler, builder Comprehensible, Configurable, Flexible Works with Scala since Gradle v1.7 With Gradle, building WAR files is very straightforward

Page 10: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Scala Language

var age: Int = 37 val pi: Double = 3.141596527 val text: String = "human nature" val r = if (age >= 18 ) "Adult" else "Child"

10  

Page 11: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Scala Test #1

import collection.mutable.Stack import org.scalatest._ import org.scalatest.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) class StackSpec extends FlatSpec with Matchers { /* ... */

}

11  

Page 12: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Scala Test #2

class StackSpec extends FlatSpec with Matchers { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() should be (2) stack.pop() should be (1) } /* ... */ }

12  

Page 13: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Scala Test #3

class StackSpec extends FlatSpec with Matchers { /* ... */ it should "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[Int] a [NoSuchElementException] should be thrownBy {

emptyStack.pop() } } }

13  

Page 14: BOF2644 Developing Java EE 7 Scala apps

Xenonique 14  

Java EE 7 released 2013 Built products on top of a standard platform Transactions, Concurrency, Remote Endpoints, Lifecycle, State, Persistence

Java is a programming language. Java is a virtual machine. Java is a platform.

Page 15: BOF2644 Developing Java EE 7 Scala apps

Xenonique 15  

Java  EE  7  

Page 16: BOF2644 Developing Java EE 7 Scala apps

Xenonique 16  

Page 17: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Context & Dependency Injection

•  Writing Scala beans •  Annotate with Scala @BeanProperty on

POSI (Plain Old Scala Instances) •  Ensure compatibility with Java code •  @BeanProperty exposes properties to CDI

17  

Page 18: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Plain Old Scala Instance

@ApplicationScoped class CashierService { @BeanProperty @Inject() var service: PaymentService = _ def process( acc: Account, amount: BigDecimal): Unit = { service.debit(amount); acc.balance = acc.balance - amount } }

18  

Page 19: BOF2644 Developing Java EE 7 Scala apps

Xenonique

CDI Dependent Object

@ApplicationScoped class PaymentService { var message: String = _ def debit(amount: BigDecimal): Unit = { message = s"You paid ${amount}" } } // Note String interpolators

19  

Page 20: BOF2644 Developing Java EE 7 Scala apps

Xenonique

CDI Model instance

class Account( var balance: BigDecimal ) // This is a complete class definition! ;-)

20  

Page 21: BOF2644 Developing Java EE 7 Scala apps

Xenonique

CDI Scala Gotchas •  Companion Objects cannot be used •  Case Classes (and obviously Case Objects) – Failure due to creation of multiple static methods

in byte code

•  Implicit class parameters •  Implicit method parameters •  Lazy public vals also fail

21  

Page 22: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Building Java EE 7 War Files •  Gradle allows developers to build WAR files

very easy and also add customisation •  Explicitly include the Scala Library JAR as a

dependency •  With SBT, it is harder to create WAR files – Battling between *.scala and *.sbt files

22  

Page 23: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Sample Gradle Dependencies

dependencies { providedCompile 'javax:javaee-api:7.0’ compile 'org.scala-lang:scala-library:2.11.2' testCompile 'junit:junit:4.11' testCompile 'org.scalatest:scalatest_2.11:2.2.0’ }

23  

Page 24: BOF2644 Developing Java EE 7 Scala apps

Xenonique

CDI Factory #1

trait Maker { def createSample(): Fruit } @ApplicationScoped class FruitFactory { private class CocktailMaker extends Maker { override def createSample():Fruit = new Strawberry } private class FruitSaladMaker extends Maker { override def createSample():Fruit = new Banana } }

24  

Page 25: BOF2644 Developing Java EE 7 Scala apps

Xenonique

CDI Factory #2

@ApplicationScoped class FruitFactory { // ... @Produces def generateCocktail(): Maker = new CocktailMaker() @Produces def generateFruitSalad(): Maker = new FruitSaladMaker() }

25  

Page 26: BOF2644 Developing Java EE 7 Scala apps

Xenonique

CDI Factory #3

trait Fruit { val price: Double; val name = this.getClass.getSimpleName } case class Apple() extends Fruit { override val price = 0.75 } case class Banana() extends Fruit { override val price = 0.95 } case class Strawberry() extends Fruit { override val price = 2.99 }

26  

Page 27: BOF2644 Developing Java EE 7 Scala apps

Xenonique

#1 Collection Of Case Classes

@ApplicationScoped class FruitVendor { def sell( fruit: Fruit with Product with Serializable, quantity: Int): Double = { fruit.price * quantity } }

27  

Page 28: BOF2644 Developing Java EE 7 Scala apps

Xenonique

#2 Collection Of Case Classes

@Test def shouldPriceFruitWithQuantity(): Unit = { val fruits = List((Apple,2), (Orange,4), (Banana,5)) for ( (fruit, quantity) <- fruits) { val product = fruitVendor.sell(fruit(), quantity) assertEquals( product, fruit().price * quantity, 0.01 ) } }

28  

Page 29: BOF2644 Developing Java EE 7 Scala apps

Xenonique

#3 Collection Of Case Classes Sugaring of Supertype

scala> val list = List( Apple -> 1, Orange -> 4, Banana -> 7 ) list: List[(scala.runtime.AbstractFunction0[ Product with Serializable with Fruit] with Serializable, Int)] = List((Apple,1), (Orange,4), (Banana,7)) // [R]AbstractFunction0.apply() => R // fruit() returns the Fruit mix-in type

29  

Page 30: BOF2644 Developing Java EE 7 Scala apps

Xenonique 30  

#2 Arquillian: Prefer integration tests over unit tests. You can write Arquillian tests with Scala You cannot yet mix ScalaTest specifications

Page 31: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Writing Arquillian Tests with Scala #1

// HERE WOULD BE THE IDEAL WORLD import org.jboss.arquillian.junit.Arquillian import org.junit.runner.RunWith import org.scalatest.junit. JUnitSuite} import org.scalatest.{FlatSpecLike, Matcher} @RunWith(classOf[Arquillian], classOf[JUnitRunner]) /* ;-) */ class HelloArquillianSpec extends JUnitSuite with FlatSpecLike with Matchers { }

31  

Page 32: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Writing Arquillian Tests with Scala #2

// The Reality of the Situation in 2014 @RunWith(classOf[Arquillian]) class HelloArquillianSpec extends JUnitSuite with Matchers { // You can’t use BDD like specificationsL }

32  

Page 33: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Writing Arquillian Tests with Scala #3

// Add a companion object, generate a WAR file object HelloArquillianSpec { @Deployment def createDeployment():WebArchive = { ShrinkWrap.create( classOf[WebArchive], "test.war") .addPackage("uk.co.xenonique.digitalone") .addAsLibrary( GradleDependency.resolve(

"org.scala-lang:scala-library:2.11.1") ) .addAsLibrary( GradleDependency.resolve(

"org.scalatest:scalatest_2.11:2.2.0") ) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml”) } }

33  

Page 34: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Writing Arquillian Tests with Scala #4

// Add a companion object @RunWith(classOf[Arquillian]) class HelloArquillianSpec extends JUnitSuite with Matchers { @Inject var hello: Hello = _ @Test def shouldPrintAPoliteGreeting():Unit = { val msg = hello.hello("JavaOne 2014") // ;-) At least, we can use matchers! (msg) should be ("Hello JavaOne 2014") } }

34  

Page 35: BOF2644 Developing Java EE 7 Scala apps

Xenonique 35  

#3  Servlets  A  Java  Servlet  is  a  web  component  managed  container.  Java  Servlets  are  based  on  the  Java  technology,  they  generate  dynamic  content,  and  hence  the  container  that  manages  them  is  capable  of  delivering  dynamic  content  to  the  web  client.    

 

Page 36: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Simplest Json Servlet @WebServlet(Array("/simple")) class SimpleServlet extends HttpServlet { override def doGet(req: HttpServletRequest, resp: HttpServletResponse): Unit = { resp.setContentType("application/json”) val writer = resp.getWriter() writer.println( s""" |{ | "trackTitle": "Two Tribes", | "class": "${this.getClass().getName}", | "date": "${new Date()}" |} """.stripMargin ) } }

36  

Page 37: BOF2644 Developing Java EE 7 Scala apps

Xenonique 37  

#4 JAX-RS Easy to write in Scala Jackson Annotations, Json4S We demand Json support with seamless Scala support Jackson, especially, FasterXML is extremely helpful https://github.com/FasterXML/jackson-annotations/ For Parsing JSON from text strings, then examine Json4S https://github.com/json4s/json4s

Page 38: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Convert Posis to Json

// How do we convert this POSI to JSON // to seamlessly and easily? ;-/ class Traveller( @BeanProperty var givenName: String, @BeanProperty var familyName: String, @BeanProperty var dateOfBirth: Date , @BeanProperty var docNo: String )

38  

Page 39: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Jackson Json Jaxb Annotations

// Look at the Jackson JAX-B project for // inspiration ;-D class Traveller2( @BeanProperty @JsonProperty("givenName") var givenName: String, @BeanProperty @JsonProperty("familyName") var familyName: String, @BeanProperty @JsonProperty("dateOfBirth") var dateOfBirth: Date, @BeanProperty @JsonProperty("documentNo") var docNo: String )

39  

Page 40: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Restful Scala JAX-RS Service Endpoint

@Path("/traveller") class TravellerServiceEndpoint { @GET() @Produces(Array(MediaType.APPLICATION_JSON)) def retrieve(): Response = { val cal = Calendar.getInstance() cal.set(1986, Calendar.MAY, 21) val dob = cal.getTime val traveller = new Traveller2("Sam", "Smith", dob, "1234567890") Response.ok(traveller).build() } }

40  

Page 41: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Jackson Json Mapping With Provider

@Singleton @Provider @Consumes(Array(MediaType.APPLICATION_JSON, "application/*+json", "text/json")) @Produces(Array(MediaType.APPLICATION_JSON, "application/*+json", "text/json")) class JacksonScalaContextResolver extends JacksonJaxbJsonProvider(JacksonScalaContextResolver.getObjectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS) object JacksonScalaContextResolver { def getObjectMapper: ObjectMapper = { val mapper = new ObjectMapper with ScalaObjectMapper mapper.registerModule(new DefaultScalaModule) mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) mapper.setSerializationInclusion(Include.NON_NULL) mapper } }

41  

Page 42: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Case Classes Instances and Jackson Annotations

@JsonIgnoreProperties(Array("databaseId", "computedDeliveryDateTime")) case class Traveller3( @BeanProperty @JsonProperty("givenName") var givenName: String, @BeanProperty @JsonProperty("familyName") var familyName: String, @BeanProperty @JsonProperty("dateOfBirth") var dateOfBirth: Date , @BeanProperty @JsonProperty("documentNo") var docNo: Option[String], @BeanProperty var computedDeliveryDateTime: Date = new Date())

42  

Page 43: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Consuming of Json to Scala Case Class Instance #1

@POST() @Consumes(Array(MediaType.APPLICATION_JSON)) def store( traveller: Traveller3): Response = { if ( traveller.getDocNo().isEmpty ) { Response.status( Response.Status.BAD_REQUEST) .entity(ErrorMessage("E199", "Missing document No")) .build() } else { Response.ok().build() } }

43  

Page 44: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Case Class #2

case class ErrorMessage( @JsonProperty("id") var id: String, @JsonProperty("error") var text: String) // Renders // { "id": "E199", // "error": "Missing document No" // }

44  

Page 45: BOF2644 Developing Java EE 7 Scala apps

Xenonique 45  

#5 JSF Easy to write in Scala Conversational, FlowScoped RequestScoped, SessionScoped All types of validation are supported including BeanValidation just like Java

Page 46: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Conversational Scoped Managed Bean

@Named("wizard") @ConversationScoped class RegisterDrivingLicense extends Serializable { @Inject var conversation: Conversation = _; @BeanProperty var title: String = _ @BeanProperty var firstName: String = _ @BeanProperty var lastName: String = _ /* ... */ }

46  

Page 47: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Controller Methods

def jumpGettingStarted(): String = { beginConversation() "form1?faces-redirect=true" } def submitPage1(): String = { beginConversation() "form2?faces-redirect=true" }

47  

Page 48: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Conversational States

def beginConversation(): Unit = { if (conversation.isTransient()) { conversation.begin() } } def endConversation(): Unit = { if (!conversation.isTransient()) { conversation.end() } }

48  

Page 49: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Finish Conversational Scopes

def submitDeclarationPage(): String = { endConversation() if ( !declaration ) { // The declaration was not signed cancelApplication() } else { // Here the form is complete "end?faces-redirect=true" } }

49  

Page 50: BOF2644 Developing Java EE 7 Scala apps

Xenonique 50  

#6 JMS JMS is straight forward to code with Scala MDB is essentially an asynchronous EJB Tricky part is publishing with JMS 2.0!

Page 51: BOF2644 Developing Java EE 7 Scala apps

Xenonique

JMS with CDI Qualifiers #1

class JMSResourceProducer { @Resource(name = "jms/OrderConnectionFactory") val orderConnFactory: QueueConnectionFactory = _ @Produces @Order @Resource(name = "jms/OrderQueue") val orderQueue: Queue = _ @Produces @Order def createOrderConnection(): QueueConnection = orderConnectionFactory.createQueueConnection() /* ... */ }

51  

Page 52: BOF2644 Developing Java EE 7 Scala apps

Xenonique

JMS with CDI Qualifiers #2

class JMSResourceProducer { /* ... */ @Produces @Order def createOrderSession( @Order conn:QueueConnection): QueueSession = conn.createQueueSession( true, Session.AUTO_ACKNOWLEDGE) }

52  

Page 53: BOF2644 Developing Java EE 7 Scala apps

Xenonique 53  

Page 54: BOF2644 Developing Java EE 7 Scala apps

Xenonique 54  

#Conclusion(1) Source code is available now! https://github.com/peterpilgrim/digital-scala-javaone-2014

Page 55: BOF2644 Developing Java EE 7 Scala apps

Xenonique 55  

#Conclusion(2) Scala and Java EE 7 integrate well from an Object-Oriented point of view Java EE 8 and Lambda API promise a functional approach. Java EE 7 annotations work in Scala. The ability of Jackson annotations and a singleton provider to seamlessly handle Scala’s case classes is a wonderful addition. Arquillian almost works completely with ScalaTest.

Page 56: BOF2644 Developing Java EE 7 Scala apps

Xenonique 56  

#Conclusion(3) WAR files require the runtime Scala Library Decent server configuration using Chef and Puppet can obviate the bundling of the runtime Scala allows developers to avoid Java boilerplate Library writers should prefer to explicitly declare the return types of functions and methods

Page 57: BOF2644 Developing Java EE 7 Scala apps

Xenonique 57  

@peter_pilgrim  

uk.linkedin.com/in/peterpilgrim

2000/  

Page 58: BOF2644 Developing Java EE 7 Scala apps

Xenonique 58  

#101 Bonus Information on Scala A Powerful weapon that requires great responsibility Great developers can create apps AM #1: “Interactions and individuals over processes and tools”

Page 59: BOF2644 Developing Java EE 7 Scala apps

Xenonique

How to avoid null pointers in Scala Programming?

val greeting1: Option[String] = Some("AOTB14") val greeting2: Option[String] = None

59  

Page 60: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Pattern Matching

def checker(p : Option[String]): String = { p match { case Some(v) => v case _ => "Unexpected" } } checker(greeting1) // "Hello AOTB14" checker(greeting2) // "Unspecified"

60  

Page 61: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Scala’s generic immutable list collection type

val list: List[Int] = List(1,2,3,4) list.foreach { x => println(x) } // 1,2,3,4

61  

Page 62: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Scala’s option behaves like collection type #2

greeting1.foreach { x => println(s"Work: ${x}" ) } // Work: Hello AOTB14

greeting2.foreach { x => println(s"Work: ${x}" ) } // *** nothing happens ***

62  

Page 63: BOF2644 Developing Java EE 7 Scala apps

Xenonique

Read, Evaluate, Print, Loop •  Scala, Clojure, Groovy, Kotlin, Ceylon, Fantom All have a interpretative mode •  Java JDK does not (yet) have an official REPL (However try out javarepl.com online) •  Fingers crossed Project Kulla in JDK 9 http://blog.gmane.org/gmane.comp.java.openjdk.general

63  

Page 64: BOF2644 Developing Java EE 7 Scala apps

Xenonique

List of Creative Commons (2.0) photography attributions

https://flic.kr/p/ayqvZp https://www.flickr.com/photos/throughpaintedeyes/ Ryan Seyeau Follow 1000 Faces of Canada # 0084 - Zombie Walk - Explore! Shot during the annual Zombie Walk in Ottawa. https://flic.kr/p/Pp93n https://www.flickr.com/photos/spacesuitcatalyst/ William A. Clark Follow Measurement Measure twice, cut once. https://flic.kr/p/81dXuT https://www.flickr.com/photos/froboy/ Avi Schwab Follow Equipment used for measuring planes of crystals https://flic.kr/p/2QHt7Q https://www.flickr.com/photos/rosefirerising/ rosefirerising Follow Pierre Curie, Piezo-Electroscope

64  

Page 65: BOF2644 Developing Java EE 7 Scala apps

Xenonique

List of Creative Commons (2.0) photography attributions

https://www.flickr.com/photos/code_martial/ https://flic.kr/p/7jmU5n Tahir Hashmi Follow Developer Death 10 Programmers and a UX Designer died all of a sudden in a war room situation. They were apparently working too hard. https://www.flickr.com/photos/8268882@N06/ https://flic.kr/p/duwd1M Peter Pilgrim IMG_1481 European JUG leaders meeting in Devoxx 2013 https://www.flickr.com/photos/unicefethiopia/ https://flic.kr/p/dv4ooi UNICEF Ethiopia Follow Hamer mother and child South Omo Zone, SNNPR Hamer mother and child South Omo Zone, SNNPR. ©UNICEF Ethiopia/2005/Getachew

65  

Page 66: BOF2644 Developing Java EE 7 Scala apps

Xenonique

List of Creative Commons (2.0) photography attributions

https://www.flickr.com/photos/15216811@N06/ https://flic.kr/p/baULpM N i c o l a Follow Tree - IMG_1242 https://flic.kr/p/dwCQ7t https://www.flickr.com/photos/90585146@N08/ marsmetn tallahassee Follow IDA .. Integro-Differential Analyzer (Sept., 1952) ...item 2.. Richard Dreyfuss: Technology Has 'Killed Time' -- "In geopolitics, the removal of time is fatal." -- "And you will give up, the protection of Republican Democracy." (July 19 2010) ... https://flic.kr/p/6ZDbiZ https://www.flickr.com/photos/ingmar/ Ingmar Zahorsky Follow Traffic Jam Accidents are common on the narrow streets going through the mountains of Nepal. When such an accident occurs, traffic is often halted for up to 3-4 hours. https://flic.kr/p/opvVsg https://www.flickr.com/photos/gregbeatty/ Greg Beatty Follow Three Pillars Nikon D800 16-35MM F4.0 https://flic.kr/p/FAskC https://www.flickr.com/photos/mari1008/ mari_1008 Follow traffic jam -B Date: April,2th Address: Jiangshu Rd,Shanghai,China. Around 8:30 AM today, A little accident on YuYuan Rd and JiangSu Rd caused traffic jam.

66  

Page 67: BOF2644 Developing Java EE 7 Scala apps

Xenonique

List of Creative Commons (2.0) photography attributions

https://flic.kr/p/bpss6D https://www.flickr.com/photos/76029035@N02/ Victor1558 Follow Creative_Photoshop_HD_Wallpapers_laba.ws https://flic.kr/p/mLxu3m https://www.flickr.com/photos/astrangelyisolatedplace/ astrangelyisolatedplace Follow Office test #1. Setup fully functional. A rare 1200 no longer in production. Test run soundtracked by the only #vinyl in the office; The Sesame Street Soundtrack - a surprise present by @idinesh #technics #turntable #1200 #ocdv1 via Instagram ift.tt/1hpeUEU https://flic.kr/p/gLPhEk https://www.flickr.com/photos/stevecorey/ Steve Corey Follow Treasure Hunt, a short story (5 images)

67  

Page 68: BOF2644 Developing Java EE 7 Scala apps

Xenonique

List of Creative Commons (2.0) photography attributions

https://flic.kr/p/4JcerK https://www.flickr.com/photos/16949884@N00/ Bömmel Follow Ice Crystal Ice is nice https://flic.kr/p/dSsXiZ https://www.flickr.com/photos/jeremyhall/ Jeremy Hall Follow Called to Serve (suit and tie) https://flic.kr/p/3enERy https://www.flickr.com/photos/paolocampioni/ Paolo Campioni Follow scala Scendo (stair case spiral)

68  

Page 69: BOF2644 Developing Java EE 7 Scala apps

Xenonique

List of Creative Commons (2.0) photography attributions

https://flic.kr/p/m62gmK https://www.flickr.com/photos/lata/ -p Follow Abstraction I. From my platycerium. (Guide: Voronoi diagram) https://flic.kr/p/6WSFR4 https://www.flickr.com/photos/62337512@N00/ anthony kelly Follow big ben big ben and underground sign https://flic.kr/p/w7qef https://www.flickr.com/photos/cobalt/ cobalt123 Follow All We are Saying... (Thought for a New Year) Peace Pasta from Annie's, with peas, of course. Give Peace A Chance

69