tag:blogger.com,1999:blog-892875797999712392024-02-08T09:37:50.612-08:00Louis Botterill's mostly software and techy BlogMy mostly technical blog. An on-line journal of my activity in the IT industry and any other technical interests or techy things that happen to catch my attention.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.comBlogger68125tag:blogger.com,1999:blog-89287579799971239.post-29447968992851666292012-06-30T13:40:00.000-07:002012-07-10T00:01:10.294-07:00Introduction to Maker, part 2<b>Part 2, building our first project with Maker:</b><br />
<br />
In the second part of this series of blogs we'll turn from fetching and bootstrapping Maker itself (from sources) as covered in part 1 to actually using Maker to build a simple project. This will introduce us to the process of defining projects in Maker and in particular the key data structures and APIs involved.<br />
<br />
The first part of the series is here if you're new to this blog:<br />
<br />
<a href="http://louisbotterill.blogspot.co.uk/2012/05/introduction-to-maker-part-1.html">http://louisbotterill.blogspot.co.uk/2012/05/introduction-to-maker-part-1.html</a><br />
<br />
Ok, so starting with the basics. A Maker based build project definition is essentially a Scala file defining the project structures and dependencies. Perhaps the easiest way to get started with a project definition file is to treat it as a Scala script and let the maker script (bin/maker.sh) load the project into the Scala REPL for you.<br />
<br />
Maker can pre-compile project definitions for speed, say where a more complex build is perhaps slow in terms of loading/interpretation in the REPL. For now we'll stick to the simple case, a simple project defined in a single Scala file, loaded by the maker script. The example project used in this blog will be a simple Hello world web application. Compiling project definitions for speed will be covered later in this series of blogs.<br />
<br />
<br />
<b>Defining the application sources:</b><br />
<br />
Let's start by making a directory to hold the whole project. We'll call it testwebapp.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$mkdir testwebapp</span><br />
<br />
While we're at it, let's make the directory structures for the source code.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$mkdir -p src/main/scala</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$mkdir -p src/main/webapp</span><br />
<br />
The location of the source directories and output directories is configurable in Maker. The default is a standard Maven style layout. Layouts are easy to customise and other layouts can be defined, more on this later.<br />
<br />
<br />
<b>Ivy files:</b><br />
<br />
Maker uses Ivy for dependency management, so lets add an Ivy settings file to define the settings for Ivy (resolvers and properties, etc). Using your favourite editor, create the file <b>ivysettings.xml</b> in the root of the testwebapp directory.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$vi ivysettings.xml</span><br />
<br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><ivysettings>
<property name="test" value="webapp" />
<property name="jetty_version" value="7.6.3.v20120416" />
<settings>
<settings name="default" transitive="false"/>
</settings>
<settings defaultResolver="default"/>
<resolvers>
<ibiblio name="central" m2compatible="true"/>
<chain name="default" returnFirst="true">
<resolver ref="central"/>
</chain>
</resolvers>
</ivysettings>
</code></pre>
<br />
<span style="background-color: white;">The above defined the version of Jetty we want to use as a property, turns off transitive dependencies and defines the name of the resolver we want to use (Maven central). This blog isn't meant to be a tutorial on Ivy, but it's fairly simple to get to grips with and you can find documentation here as required. Many concepts are similar to those in Maven, so if you've ever user Maven then you won't feel too out of place.</span><br />
<br />
[A quick aside on transitive dependencies; Whilst transitive dependencies can be used (since Maker uses Ivy and Ivy it supports this feature) a suggestion would be to switch this feature off and define dependencies explicitly - that way there can be no nasty surprises as your projects grow in size and complexity]<br />
<br />
Let's now define the ivy.xml file. This defines the dependencies specific to the project module. Generally in a single build there would be one <b>ivysettings.xml</b> and then one <b>ivy.xml</b> per project module (that has external dependencies).<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$vi ivy.xml</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><ivy-module version="1.0" xmlns:e="http://ant.apache.org/ivy/extra">
<info organisation="${group_id}" module="utils" revision="${maker.module.version}" />
<configurations>
<conf name="default" transitive="false"/>
<conf name="compile" transitive="false"/>
<conf name="test" transitive="false"/>
</configurations>
<publications>
<artifact name="test-webapp" type="pom"/>
<artifact name="test-webapp" type="jar" ext="jar" conf="default" />
</publications>
<dependencies defaultconfmapping="*->default,sources">
<dependency org="log4j" name="log4j" rev="1.2.16" />
<dependency org="org.slf4j" name="slf4j-api" rev="1.6.1"/>
<dependency org="org.slf4j" name="slf4j-log4j12" rev="1.6.1" />
<dependency org="org.eclipse.jetty" name="jetty-server" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-webapp" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-util" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-servlet" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-security" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-http" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-io" rev="${jetty_version}" />
<dependency org="org.eclipse.jetty" name="jetty-xml" rev="${jetty_version}" />
<dependency org="javax.servlet" name="servlet-api" rev="2.5" />
</dependencies>
</ivy-module>
</code></pre>
<div>
<br />
ivysettings.xml and ivy.xml are the default file names Maker will look for when using Ivy to resolve dependencies. Again the name and location of these defaults can be changed.</div>
<br />
<div>
Ok, so now we have put the files necessary for Ivy in place and the source directory structure, lets have a look at defining a minimal Maker project file.</div>
<br />
<br />
<b>Creating a Maker project definition:</b><br />
<br />
<span style="background-color: white;">Create a file called say <b>maker.scala</b>, in the root of the project directory.</span><br />
<br />
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$vi maker.scala</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><a href="http://www.blogger.com/goog_158347219"><br /></a></span></div>
<div>
<div>
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.project.Project</span></div>
<div>
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.utils.FileUtils._</span></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.Props</span></div>
</div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><a href="http://www.blogger.com/goog_158347219"><br /></a></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">lazy val properties : Props = file("Maker.conf")</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><a href="http://www.blogger.com/goog_158347219"><br /></a></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">val webApp = Project(</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> file("."),</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> "test-webapp", </span></div>
<div>
<span style="background-color: white;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> props = properties,</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> webAppDir = Some(file(".", "src/main/webapp"))</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">)</span><br />
<br /></div>
<div>
</div>
<div>
So this file defines one Maker project, called "test-webapp", as an instance called webApp. Maker projects take a number of arguments but most can be defaulted. At a minimum just the project root directory must be specified. Since we're making this project a single self contained project, the root directory is just the current project directory. The presence of the webAppDir means this application will be treated as a web application, not a regular jar module. In case you're wondering, file(...) is just one of a number of helper function defined in the object maker.utils.FileUtils that make working with Java files a bit less tedious.<br />
<br />
A Maker Project is a regular Scala case class defining a build module. All tasks, such as clean, compile and test are invoked on a project instance.</div>
</div>
<div>
<a href="http://www.blogger.com/goog_158347219"><br /></a></div>
<div>
The key parameters to a Maker Project definition are:</div>
<div>
<ul>
<li><span style="background-color: white;">root : File - a File representing the root of this project</span></li>
<li><span style="background-color: white;">name : String - a name for the project, can be omitted in which case it defaults to the root file name</span></li>
<li><span style="background-color: white;">layout : ProjectLayout - a case class defining the file locations all all inputs (source files etc) and outputs (classes etc)</span></li>
<li><span style="background-color: white;">props : Props - a key-value property file defining any properties for maker, this may be omitted as Maker does default most properties</span></li>
<li><span style="background-color: white;">webAppDir :Option[File] -</span><span style="background-color: white;"> this is an optional file, when provided it represents the directory containing the webapp content (WEB-INF etc) and means the project acts like a web application (produces a war packaged artifact, and can be run using the embedded Jetty runner, for example).</span></li>
</ul>
</div>
<a href="http://www.blogger.com/blogger.g?blogID=89287579799971239">
</a><br />
<div>
Documentation on the Project class can be viewed here: <a href="http://cage433.github.com/maker/maker/target/docs/#maker.project.Project">http://cage433.github.com/maker/maker/target/docs/#maker.project.Project</a><br />
<br /></div>
<div>
So that's it for defining the build of a simple web application. Maker will default everything else required for a typical build.</div>
<div>
<br /></div>
<div>
Lets add some content to make this simple Hello world project functional.</div>
<div>
<br />
<br />
<b>Adding some web content:</b><br />
<br /></div>
<div>
First we'll define some static resources, a simple test web page:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$vi src/main/webapp/hello.html </span></div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><html>
<body>
Hello world - from html
</body>
</html>
</code></pre>
<br />
<div>
<span style="background-color: white;">and a simple servlet for good measure:</span></div>
</div>
<div>
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code>package test
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}
class HelloServlet extends HttpServlet {
println("Initialised HelloServlet")
override def doGet(req : HttpServletRequest, resp : HttpServletResponse) =
resp.getWriter().print("<HTML>" +
"<HEAD><TITLE>Hello, Scala!</TITLE></HEAD>" +
"<BODY>Hello, Scala! This is a servlet.</BODY>" +
"</HTML>")
}
</code></pre>
<br />
<span style="background-color: white;">and now the files necessary for the web application:</span></div>
<div>
<br /></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$ cat src/main/webapp/WEB-INF/web.xml </span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<pre style="background-color: #eeeeee; border: 1px dashed #999999; color: black; font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"><code><?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
Version="2.5">
<display-name>Test webapp</display-name>
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>
test.HelloServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/servlets/hello</url-pattern>
</servlet-mapping>
</web-app>
</code></pre>
<br />
<span style="background-color: white;"><span style="font-family: inherit;">Which wires up our test servlet. So that's all the plumbing to put together a trivial test hello-world web application.</span></span></div>
<div>
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><b>Booting the project in Maker:</b></span><br />
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Let's now boot Maker with the project definition. This is done by running the bin/maker.sh script that you should have from part one of this blog. Unlike in the last part where we used the -b switch to get Maker to build and bootstrap itself from sources, we're now using that build Maker to load a user defined project, with the -p option.</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$path/to/maker/bin/maker/.sh -p $path/to/testwebapp/maker/scala</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;">for example, if Maker was a sibling to our test project directory, we might type the following from the root of the test project directory:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$ ../maker/bin/maker.sh -p maker.scala </span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;">remembering that the maker.sh script is the entry point for maker and the -p option specifies a Maker project definition file to load - you should be greeted with the following REPL prompt:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Loading maker.scala...</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import org.apache.log4j.Level._</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.project.Project</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.Props</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.RichProperties._</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.utils.FileUtils._</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.utils.Log</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">makerProps: maker.Props = <lazy></lazy></span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">webApp: maker.project.Project = Project org.acme:test-webapp</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33).</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Type in expressions to have them evaluated.</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Type :help for more information.</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">scala></span></span></div>
</div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;"><b>Updating and compiling:</b></span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">From here we can issue Maker commands as required. If you type webApp (the name of our project instance) and the dot (.) and then tab you should get a list of available methods. There are many, but some will jump out as immediately familiar, such as clean, test and so on. For a new project, the first thing to do is invoke Ivy to update any project dependencies:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">scala> webApp.update</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;">which should then output some details about the dependencies as they are resolved (via Ivy) and downloaded, ending in some output like:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></span></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">:: retrieving :: ${group_id}#utils [sync]</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> confs: [default]</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> 24 artifacts copied, 0 already retrieved (3001kB/90ms)</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">24 Jun 2012 22:58:57:682 INFO root - Completed ProjectAndTask(Project org.acme:test-webapp,UpdateTask), took 409(ms)</span></span></div>
</div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">result was Success</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">There are two things to note here, by default;</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">1 Maker only invokes Ivy when instructed (this can be overridden to be fully automatic before compilation)</span></div>
<div>
<span style="font-family: inherit;">2 Maker puts the dependencies in a sub-directory of the project, by default called lib_managed (like SBT) - again this is configurable as you'll see shortly</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">We can check this. Every Maker project has a layout, by default Maker uses the Maven style layout. Within the layout is a definition of where the managed libraries go (managed libraries being the name of those 'managed' by Ivy, as opposed to user managed libraries that have been provided by hand) </span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<div>
<span style="font-family: inherit;">Within a project's layout the field called managedLibDir is a regular java.io.File, so we could use it perhaps to list the files in that directory:</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">scala> webApp.layout.managedLibDir.listFiles.foreach(println)</span></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-http-7.6.3.v20120416-sources.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-http-7.6.3.v20120416.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-io-7.6.3.v20120416-sources.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-io-7.6.3.v20120416.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-security-7.6.3.v20120416-sources.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-security-7.6.3.v20120416.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-server-7.6.3.v20120416-sources.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-server-7.6.3.v20120416.jar</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">./lib_managed/jetty-servlet-7.6.3.v20120416-so</span></span></div>
</div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span></div>
<div>
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">These are the dependency files that Maker has fetched for our project (using Ivy) and put in the lib_managed directory of our project. Of course these libraries will be cached in the ~/.ivy2 Ivy cache directory first, so once populated the libraries will only be fetched from the Internet when new dependencies are added. All unmanaged and managed libraries are added to the classpath for compilation and to packaged artifacts (e.g. .wars) as would be expected.</span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">Ok, so far so good. Now we have a loaded project with dependencies resolved, we can compile it:</span><br />
<span style="font-family: inherit;"><br /></span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">scala> webApp.compile</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:21:21 INFO - Starting task test-webapp, Source compile, press ctrl-] to terminate</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:21:23 INFO - Completed test-webapp, Source compile, took 1(s) 563(ms)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">res1: maker.task.BuildResult = </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">test-webapp, Source compile result was Success</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Project: Project org.acme:test-webapp</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> Task : Source compile</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">scala> </span><br />
<br />
So the project has compiled ok, in around 1.5s in my machine.<br />
<br />
If we had added some tests then we could run webApp.test to compile and run the tests - but as we've not added any for this simple example we'll skip this step.<br />
<br />
The presence of the webAppDir on the project definition triggers certain web application specific features that are not available for standard Java projects. For example, webApp.package will package up a standard format <b>W</b>eb<b>AR</b>chive (.war) file for us rather than a <b>J</b>ava<b>AR</b>chive (.jar).<br />
<br />
<br />
<b>Running the web-app within Maker:</b><br />
<br />
For web applications, Maker can run the application using an embedded Jetty container using the runJetty task. By default this runs your project Jetty on port 8080, but a new port number can optionally be supplied to the task if required.<br />
<br />
So let's give that a go now.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">scala> webApp.runJetty</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - Starting task test-webapp, RunJettyTask, press ctrl-] to terminate</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - </span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Packaging project dirs:</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - /Users/louis/dev/projects/opensource/github/testwebapp/./src/main/resources</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - /Users/louis/dev/projects/opensource/github/testwebapp/./target/classes</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - Packaging web app, web app dir = /Users/louis/dev/projects/opensource/github/testwebapp/./src/main/webapp</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - Making war image.../Users/louis/dev/projects/opensource/github/testwebapp/./target/package/webapp</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:29 INFO - Packaging artifact /Users/louis/dev/projects/opensource/github/testwebapp/./target/package/test-webapp.war</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:30 INFO - running webapp of project test-webapp</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:31 INFO - Starting HTTP on port: 8080</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:31 INFO - jetty-7.6.3.v20120416</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:31 INFO - Extract jar:file:/Users/louis/dev/projects/opensource/github/testwebapp/target/package/test-webapp.war!/ to /private/var/folders/wv/s7b3m27j39sbct3d97rhs8km0000gn/T/jetty-0.0.0.0-8080-test-webapp.war-_test-webapp-any-/webapp</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SLF4J: Class path contains multiple SLF4J bindings.</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SLF4J: Found binding in [jar:file:/private/var/folders/wv/s7b3m27j39sbct3d97rhs8km0000gn/T/jetty-0.0.0.0-8080-test-webapp.war-_test-webapp-any-/webapp/WEB-INF/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SLF4J: Found binding in [jar:file:/Users/louis/dev/projects/opensource/github/maker/.maker/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:33 INFO - started o.e.j.w.WebAppContext{/test-webapp,file:/private/var/folders/wv/s7b3m27j39sbct3d97rhs8km0000gn/T/jetty-0.0.0.0-8080-test-webapp.war-_test-webapp-any-/webapp/},/Users/louis/dev/projects/opensource/github/testwebapp/./target/package/test-webapp.war</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">Initialised HelloServlet</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:33 INFO - Started SelectChannelConnector@0.0.0.0:8080</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">14:26:33 INFO - Press ctrl-] to end...</span><br />
<div>
<br /></div>
<br />
<br />
Now Jetty is running and Maker is waiting for that process to finish. Since Web Applications don't really terminate from inside the user code, the way to quit this long-running process is to type <b>ctrl-]</b> when we're done. Don't do that just yet, we'll check it works first.<br />
<br />
From your favourite browser we should be able to view the web content here.<br />
<br />
<a href="http://localhost:8080/test-webapp/">http://localhost:8080/test-webapp/</a><br />
<br />
and the static web page here:<br />
<br />
<a href="http://localhost:8080/test-webapp/hello.html">http://localhost:8080/test-webapp/hello.html</a><br />
<br />
and the servlet using:<br />
<br />
<a href="http://localhost:8080/test-webapp/servlets/hello">http://localhost:8080/test-webapp/servlets/hello</a><br />
<br />
Ok, so it works. Press ctrl-] in the REPL to quit the Jetty runner and return to the REPL prompt.<br />
<br />
So far so good. We've seen how to define a simple project (a web application in this example) and define the necessary minimal Maker project definition necessary to build, test and run it.<br />
<br />
Before we wrap up this second bog in the series, it's worth just highlighting the project layout as it's quite likely you might want to customise it for your real-world projects at some stage.<br />
<br />
<br />
<b>Customising project layouts:</b><br />
<br />
Within Project, the layout field is a ProjectLayout (as mentioned earlier). Maker currently provides two default layouts; 'maven' and 'maker', these are regular values (val fields) in the companion ProjectLayout class. The default maven layout follows the standard maven layout in terms of sources and output classes. Similarly the maker layout is similar but 'flattened' out and is the layout maker uses for its own project.<br />
<br />
Any existing layout can be modified, or you're free to create your own instance of ProjectLayout in any way you want to meet your project needs. Being a simple case class we can use the free copy function to make modifications to the immutable class.<br />
<br />
Here's a quick example. Say we want a Maven based layout, but with a couple of changes. We want to add another source directory and rename the managed lib directory - this is one way to do that:<br />
<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span><br />
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;">import maker.utils.FileUtils._</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">def myLayout(root : File)<span style="background-color: white;"> = { </span></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> val layout = ProjectLayout.maven(root)</span><br />
<span style="font-size: x-small;"><span style="font-family: 'Courier New', Courier, monospace;"> layout.copy(</span><span style="background-color: white;"><span style="font-family: 'Courier New', Courier, monospace;">sourceDirs = new File(root, "my_extra_src") :: layout.sourceDirs, managedLibDir = file(root, "managed_libs))</span></span></span><br />
<span style="background-color: white;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">}</span></span><br />
<span style="background-color: white;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="background-color: white;">val webApp = Project(</span></span><br />
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> file("."),</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> "test-webapp",</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> layout = myLayout(file("."))</span></div>
<div>
<span style="background-color: white;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> props = properties,</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> webAppDir = Some(file(".", "src/main/webapp"))</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
Also layout has some utility functions, so to just add a source directory we might more concisely do this:<br />
<br />
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span><br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="background-color: white;"><br /></span></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><span style="background-color: white;">val baseWebApp = Project(</span></span><br />
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> file("."),</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> "test-webapp",</span></div>
<div>
<span style="background-color: white;"><span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> props = properties,</span></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> webAppDir = Some(file(".", "src/main/webapp"))</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">val webApp = baseWebApp.copy(</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"> layout = baseWebApp.layout.withSourceDirs(List("src1", "src2").map(file(baseWebApp.root, _))</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">...</span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="background-color: white;">Any attribute of the layout can be customised in this way, or you might want to define new layouts from scratch if they are significantly different from those provided.</span><br />
<span style="background-color: white;"><br /></span><br />
<span style="background-color: white;">Documentation on the layout class: <a href="http://cage433.github.com/maker/maker/target/docs/#maker.project.ProjectLayout">http://cage433.github.com/maker/maker/target/docs/#maker.project.ProjectLayout</a></span></div>
<br />
<span style="font-family: inherit;">Now that we've covered project definitions and using maker to compile and run, a few quick words on properties. </span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">Maker provides defaults for most parameters so that it works out-of-the-box with minimal configuration, but most aspects can be configured either using properties or via optional arguments to the tasks.</span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">In our simple maker project definition you'll notice that we created a Maker.conf based Props class and passed it to the project.</span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><b>Maker properties:</b></span><br />
<span style="font-family: inherit;"><br /></span><br />
Various things can be configured using the property file. For example it was previously mentioned that the default Ivy update on compile could be changed. So in this example we could achieve that by adding the property to the Maker.conf file.<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">$vi Maker.conf</span><br />
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: x-small;">UpdateOnCompile=true</span><br />
<br />
<span style="font-family: inherit;">Now when we run any task that compiles (or depends on compilation) the Ivy update task will run first.</span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><b>Wrapping up:</b></span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">That about concludes this second blog in the series of byte-sized introductions to Maker. We've still not covered several key aspects, but these should get covered in up and coming blogs of this series. Some of the topics still to be covered are:</span><br />
<ul>
<li><span style="background-color: white;">Accessing Maker documentation</span></li>
<li><span style="background-color: white;">Continually running tasks - e.g. being able to run tests continually while you develop code to make them pass</span></li>
<li><span style="background-color: white; font-family: inherit;">Testing - how unit tests can be run and inspected. Re-running failing tests</span></li>
<li><span style="background-color: white; font-family: inherit;">Packaging - examples of how packaging works and what can be configured to give different packaging options</span></li>
<li><span style="background-color: white; font-family: inherit;">Documentation - producing scala-doc documentation from Maker projects</span></li>
<li><span style="background-color: white; font-family: inherit;">Publishing - how to publish Maven style artifacts from Maker to repositories like Nexus.</span></li>
<li><span style="background-color: white;">Analyzing<span style="font-family: inherit;"> failures - identifying compilation or test problems, inspecting build results in detail</span></span></li>
<li><span style="background-color: white; font-family: inherit;">Dependency analysis - viewing dependency graphs and querying dependencies</span></li>
<li><span style="background-color: white;">Compiling project files - for speed of Maker start up</span></li>
</ul>
And, finally - I'd like to cover getting started with Maker as a packaged tool, distributed from binaries - but we're still working on this part. So for now the sequence described in blog part one is a valid way to 'bootstrap' maker straight from sources. Hopefully we'll have a good solution for using Maker from a binary distribution soon and a forthcoming blog will then cover how to install and use it in this way.<br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;">Documentation: Scala-docs from Github can be found here: </span><span style="background-color: white;"><a href="http://cage433.github.com/maker/maker/target/docs/">http://cage433.github.com/maker/maker/target/docs/</a></span><br />
<span style="font-family: inherit;"><br /></span><br />
<span style="font-family: inherit;"><br /></span><br />
Now you've seen how easy it is to start using Maker to compile your Scala and Java projects, what are you waiting for - get using it and please give us your valuable feedback!<br />
<br />
Any problems, issue tracking is on GitHub: <a href="https://github.com/cage433/maker/issues?sort=created&state=open">https://github.com/cage433/maker/issues?sort=created&state=open</a><br />
<br />
<a href="http://louisbotterill.blogspot.co.uk/2012/05/introduction-to-maker-part-1.html"><<< introduction to maker part 1</a><br />
<br />
<br /></div>LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-10710437830799448952012-05-12T04:05:00.001-07:002012-07-21T00:41:42.968-07:00Introduction to Maker, part 1<br />
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>Introduction to Maker, part 1:</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>Maker</b>
- A simple build system for Scala (and Java) projects</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Maker
is a fast, yet simple, command line </span><span style="font-family: 'Times New Roman';">build </span><span style="font-family: 'Times New Roman';">system for development of
Scala (and Java) projects.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>Main
features, at a glance:</b></span></div>
<ul>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Fast, incremental,
parallel compilation. Maker will utilize as many cores as you have available to parallelise non-sequential module dependencies</span></div>
</li>
<li><span style="font-family: 'Times New Roman';">Simple, flexible project configuration and APIs</span></li>
<li><span style="font-family: 'Times New Roman';">Standard interactive REPL based session</span></li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Integrated dependency
management (delegated to and handled by Ivy)</span></div>
</li>
<li><span style="font-family: 'Times New Roman';">Test
Runner integration</span></li>
<li><span style="font-family: 'Times New Roman';">Can transparently run 'offline'</span></li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Supports
web-applications, with embedded Jetty runner</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Integrates
with Maven and Nexus for standard artifact publishing</span></div>
</li>
</ul>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>So
why Maker?</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">If
you work with Scala, SBT is the natural build system everyone tends to
gravitate towards. However the <b>S</b> in <b>S</b>BT once stood for <b>S</b>imple. Since the
changes from .1x onwards this is perhaps less so. While SBT is
powerful, its APIs and dependency management can be opaque and
difficult to understand and get right (particularly on large projects).</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Maker
aims to put the '<b>S</b>imple' back into a build tool for Scala, whilst still
retaining the performance and feature set we've come to expect from a
modern build tool.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Whilst
still very much a work in progress, we are dog-food-ing this build
system on our own project and we're almost at the point where we'll switch
out SBT 0.1x for this replacement. Maker should be able to build projects of all sizes, but as with all new projects there may be some feature gaps - these should be closed down over time.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>Maker
resource quick-links:</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">GitHub:
<a href="https://github.com/cage433/maker">https://github.com/cage433/maker</a>
home and readme: <a href="https://github.com/cage433/maker#readme">https://github.com/cage433/maker#readme</a></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">GitHub, Issues and feature tracking:
<a href="https://github.com/cage433/maker/issues?direction=desc&sort=created&state=open">https://github.com/cage433/maker/issues?direction=desc&sort=created&state=open</a></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">GitHub
Wiki: <a href="https://github.com/cage433/maker/wiki">https://github.com/cage433/maker/wiki</a></span><br />
<br />
<span style="font-family: Times, 'Times New Roman', serif;">Jenkins continuous integration: <a href="http://www.chillipower.com:8081/">http://www.chillipower.com:8081</a></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;"><br /></span><br />
<span style="font-family: Times, 'Times New Roman', serif;">Google
code: <a href="http://code.google.com/p/maker/">http://code.google.com/p/maker/</a></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">By
means of an example of bootstrapping maker and using it to build itself, this blog is aimed at the
beginner and will hopefully show the basics of getting started. So
here goes.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Getting
started; getting the code and bootstrapping the build:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Maker
is in GitHub, using a Git client, clone the repo:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>$
git clone git@github.com:cage433/maker.git maker</b></span></div>
<div style="margin-bottom: 0cm;">
<b><br />
</b></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>$
cd maker</b></span></div>
<div style="margin-bottom: 0cm;">
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Maker
is launched through a single script, this is bin/maker.sh, we can get a list of options using --help:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>maker$
bin/maker.sh --help</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">usage</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">maker.sh
<option>*</option></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">options</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-h,
--help</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-p,
--project-file <project-file></project-file></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-c,
--cmd</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">run
command directly then quit</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-j,
--use-jrebel (requires JREBEL_HOME to be set)</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-m,
--mem-heap-space <heap in="" mb="" space=""> </heap></span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">default
is one quarter of available RAM</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-y,
--do-ivy-update </span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">update
will always be done if <maker-dir>/.maker/lib doesn't exist</maker-dir></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-b,
--boostrap </span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">builds
maker.jar from scratch</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-d,
--download-project-scala-lib </span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">downloads
scala compiler and library to <project-dir>/.maker/scala-lib</project-dir></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">download
is automatic if this directory does not exist</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-x,
--allow-remote-debugging</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">runs
a remote JVM</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-i,
--developer-mode</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">For
maker developers.</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Sets
the maker classpath to maker/classes:utils/classes etc rather than </span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">maker.jar.
Allows work on maker and another project to be done simultaneously.</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-nr,
--no-repl</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">skip
repl launch (just performs bootstrapping/building and returns)</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">-ntty,
--no-tty-restore</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">skip
save and restore tty (for integration with automation such as
TeamCity reporting)</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">--args,
--additional-args</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">additional
variable length argument list to pass to JVM process directly. Must
come at the end of the arguments</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">--mem-permgen-space
<space in="" mb=""></space></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">default
is 1/10th of heap space</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">--ivy-proxy-host
<host></host></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">--ivy-proxy-port
<port></port></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">--ivy-non-proxy-hosts
<host,host,...></host,host,...></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">--ivy-jar
<file> </file></span>
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">defaults
to /usr/share/java/ivy.jar</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Now
we can bootstrap maker by building a maker jar lib, this is done through
the main maker script</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>maker$
bin/maker.sh -y -b</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>-y</b> tells maker to fetch dependency libraries required by maker</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';"><b>-b</b> tells maker to bootstrap itself using a brute force build from
sources</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">(note,
if you're connecting to the internet via a proxy you might also need
to specify –ivy-proxy-host and –ivy-proxy-port options).</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">This
should take a few seconds and then you'll find yourself in the
probably familiar Scala repl.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">At
this stage maker has fetched dependencies, built the maker jar and booted it on the classpath. If you want to
just use it to make another project then you could quit and start
using it immediately (which I'll show in a subsequent blog of this series)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">But
while we're here, lets take a quick look around…</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Maker
has the standard concept of projects which can be viewed as modules of
software compilation. These projects can be joined up in a dependency
tree – just as you would expect from a build tool. In maker's own project definition, the
parent module is called mkr and we can check that in the repl:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res3:
maker.project.Project = Project com.google.code.maker:maker</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Here
we see that the project is defined as an instance of the class
maker.project.Project</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Projects
are where all the action happens. Now that we've bootstrapped maker,
we can ask Maker to actually build itself! </span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Note on Ivy: By
default, updating dependencies from Ivy automatically is disabled (it
can be enabled by default using Maker properties, more on that later). So to update
Maker's dependencies (makers own build is separated from the
bootstrap classpath) we can use the update command on the project.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.update</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">::
loading settings :: file = maker-ivysettings.xml</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">::
loading settings :: file = maker/maker-ivy-dynamic.ivy</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">...</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">::
resolving dependencies ::
com.google.code.maker#utils;${maker.module.version}</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> confs:
[default]</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
log4j#log4j;1.2.16 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
commons-io#commons-io;2.1 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
com.typesafe.akka#akka-actor;2.0 in akka</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
com.typesafe.akka#akka-remote;2.0 in akka</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
com.typesafe.akka#akka-kernel;2.0 in akka</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.scala-tools.testing#scalacheck_2.9.1;1.9 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.scalatest#scalatest_2.9.1;1.7.1 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.scalaz#scalaz-core_2.9.1;6.0.4 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.slf4j#slf4j-api;1.6.1 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.slf4j#slf4j-log4j12;1.6.1 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.apache.ant#ant;1.8.2 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
io.netty#netty;3.4.2.Final in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
com.google.protobuf#protobuf-java;2.4.1 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
net.debasishg#sjson_2.9.1;0.15 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
voldemort.store.compress#h2-lzf;1.0 in akka</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-server;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-webapp;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-util;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-servlet;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-security;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-http;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-io;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-xml;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-continuation;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.eclipse.jetty#jetty-jsp;7.6.3.v20120416 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.mortbay.jetty#jsp-2.1-glassfish;2.1.v20100127 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
javax.servlet#servlet-api;2.5 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.apache.tomcat#jsp-api;6.0.20 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> found
org.mockito#mockito-all;1.8.2 in central</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">::
resolution report :: resolve 1022ms :: artifacts dl 74ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> ---------------------------------------------------------------------</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> |
| modules || artifacts |</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> |
conf | number| search|dwnlded|evicted|| number|dwnlded|</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> ---------------------------------------------------------------------</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> |
default | 29 | 0 | 0 | 0 || 54 | 0 |</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> ---------------------------------------------------------------------</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">::
retrieving :: com.google.code.maker#utils [sync]</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> confs:
[default]</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"> 0
artifacts copied, 54 already retrieved (0kB/43ms)</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:35:28 INFO root - Task[utils:UpdateTask] completed in
1256ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:35:28 INFO root - Completed Task[maker:UpdateTask],
took 1(s) 720(ms)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res4:
maker.task.BuildResult[AnyRef] = OK</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">What
you should see (assuming you have connectivity to the internet) is a
set of resolved dependencies for Maker and most importantly the
<b>BuildResult = OK</b> at the end.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Whilst
this project has not yet compiled before, if it had, we might first clean it
using:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.clean</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:37:43 INFO root - Task[maker:CleanTask] completed in
131ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:37:43 INFO root - Completed Task[maker:CleanTask], took
214(ms)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res5:
maker.task.BuildResult[AnyRef] = OK</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Ok,
let's now compile Maker using itself, as a test:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.compile</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:37:46 INFO root - Compiling Project
com.google.code.maker:utils</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">warning:
there were 2 unchecked warnings; re-run with -unchecked for details</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:38:04 INFO root - Task[utils:CompileSourceTask]
completed in 18638ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:38:04 INFO root - Compiling Project
com.google.code.maker:plugin</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:38:10 INFO root - Task[plugin:CompileSourceTask]
completed in 5319ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:38:10 INFO root - Compiling Project
com.google.code.maker:maker</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">warning:
there were 6 unchecked warnings; re-run with -unchecked for details</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:38:29 INFO root - Task[maker:CompileSourceTask]
completed in 18852ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:38:29 INFO root - Completed
Task[maker:CompileSourceTask], took 42(s) 813(ms)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res6:
maker.task.BuildResult[AnyRef] = OK</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">All
build commands in Maker are functions that return results, for
example, from the <i>compile </i>command we get a result that we can use and inspect. We can even get this result into a named variable and use it
in other expressions.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Running
compile again will also demonstrate the incremental compilation, note
the second compile completes almost instantly and there is no further
compilation reported because we are all up to date.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
val r = mkr.compile</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:39:52 INFO root - Completed
Task[maker:CompileSourceTask], took 113(ms)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">r:
maker.task.BuildResult[AnyRef] = OK</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
r.stats.foreach(println)</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Task[maker:CompileSourceTask],
took 57ms, status OK</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Task[plugin:CompileSourceTask],
took 25ms, status OK</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Task[utils:CompileSourceTask],
took 26ms, status OK</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Projects
have all the normal tasks you'd expect available on them as
functions, the main tasks being:</span></div>
<ul>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">clean
– clean up the compilation state (remove classes etc)</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">compile -
compile the main source code</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">testCompile
– compile the test source code</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">test
– run all tests</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">testClass
– run a specific test class (or test suite name) by name</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">pack
– package up the modules into jars (or wars for webapps)</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">update
– update dependency libraries</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">publishLocal
– publish artifacts to the local file system</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">publish
– publish artifacts to a remote repo</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">runMain
– run a main class</span></div>
</li>
<li><div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">runJetty
– run the module as a web-app (uses embedded Jetty within Maker) </span>
</div>
</li>
</ul>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Most
of these tasks also have a corresponding [<i>taskname</i>]<b><i>Only</i></b> counterpart which runs the
task only on the module and not on any descendent modules. By default, all tasks first run on dependency modules as appropriate, as would be expected. Similarly, tasks may depend on each other. For example, <i>project.test</i> will ensure all child modules are compiled and their tests are compiled before starting the tests.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">It's
also possible to run compilation, all tests, individual tests, and
main methods continuously, say for development purposes while you work on code to make a particular test pass.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">We
can inspect project module dependencies, for example:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.children</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res3:
List[maker.project.Project] = List(Project
com.google.code.maker:plugin)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">where
the returned value is a list of child projects that this project <b>directly</b>
depends on.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">We
can also see all dependencies including indirect dependencies using:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.allDeps</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res4:
List[maker.project.Project] = List(Project
com.google.code.maker:maker, Project com.google.code.maker:plugin,
Project com.google.code.maker:utils)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;">Here we see that mkr depends on plugin and utils (these are all the project modules in maker).</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;"><br />
</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;">We
can inspect library dependencies, for example:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.classpathDirectoriesAndJars.foreach(println)</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">maker/classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">maker/java-classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">maker/test-classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">/Users/louis/dev/tools/scala/scala/lib/scala-compiler.jar</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">/Users/louis/dev/tools/scala/scala/lib/scala-library.jar</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">maker/resources</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">plugin/classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">plugin/java-classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">plugin/test-classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">plugin/resources</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">utils/classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">utils/java-classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">utils/test-classes</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">libs/ivy-2.2.0-sources.jar</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">libs/ivy-2.2.0.jar</span></div>
<div style="margin-bottom: 0cm;">
…</div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman';">Let's
run Maker's tests, to check all is good:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
val r = mkr.test</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b><br /></b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:49:58 INFO root - Compiling Project
com.google.code.maker:utils</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:49:59 INFO root - Task[utils:CompileTestsTask]
completed in 1760ms</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 09:49:59 INFO root - Testing Project
com.google.code.maker:utils</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Run
starting. Expected test count is: 9</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">MemoizeTests:</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">FileUtilsTests:</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">LogTests:</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">ProcessIDTests:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
…</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;"><br />
</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;">Output from the test runs should be displayed in the standard test output format, at the end overall success or failure is reported.
</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;"><br /></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Times, 'Times New Roman', serif;">We
can also query for a particular fragment of a library name or find
out how a module depends on a particular library:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.findLibs("scalatest")</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">utils/lib_managed/scalatest_2.9.1-1.7.1-sources.jar</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">utils/lib_managed/scalatest_2.9.1-1.7.1.jar</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">This
tells us that Maker depends on a library named scalatest, via the
<i>utils</i> module's managed library dependencies.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">We
can find the dependency path from one project module to another
using:</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>scala>
mkr.dependsOnPaths(utils)</b></span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">res15:
List[List[maker.project.Project]] = List(List(Project
com.google.code.maker:maker, Project com.google.code.maker:plugin,
Project com.google.code.maker:utils))</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">This
tells us that the project module mkr depends on the module utils via
the module path; mkr → plugin → utils</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">Maker
doesn't have a complex module structure, but in a complex tree of
module dependencies these functions can be useful when trying to
understand project structures and dependencies, perhaps for refactoring.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
</div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">One
last thing, maker can run commands from the command line without
launching the repl. As we're about done for this setting, let's drop
out of the repl and try it ( :q or ctrl-c quits the repl session in case you didn't know).</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b>maker$
bin/maker.sh -c "mkr.clean"</b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;"><b><br /></b></span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">No
project file defined, searching for a maker Scala file</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Omitting
ivy update as
/Users/louis/dev/projects/opensource/github/maker/.maker/lib exists</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Omitting
bootstrap as
/Users/louis/dev/projects/opensource/github/maker/maker.jar exists</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">setting
cmd as -e mkr.clean</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">Maker
v.1</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">12
May 2012 10:35:40 INFO root - Completed Task[maker:CleanTask], took
151(ms)</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: Courier, monospace;">returning
exit status: 0</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">There
are many more features in maker that will be explored in subsequent
blogs. At this stage we're now at least able to obtain and bootstrap maker, and
explore maker's basic features to build and test itself.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">Maker
can do more, including drawing graphical graphs of build and test results as well as
module dependencies – more on this in a future blog.</span></div>
<div style="margin-bottom: 0cm;">
<br /></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif;">In
the next blog I'll walk you through making a new project from
scratch. We'll see how to construct a new project definition and use
Maker's features to build, test, and run a simple hello-world web
application from the repl...</span></div>
<div style="margin-bottom: 0cm;">
<span style="font-family: 'Times New Roman', serif; font-size: x-small;"><br /></span></div>
<a href="http://louisbotterill.blogspot.co.uk/2012/06/introduction-to-maker-part-2.html">>>> introduction to maker part 2</a><br />
<br />LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-63218919466159949382010-02-03T10:34:00.000-08:002010-02-03T10:59:49.197-08:00GlassFish v3 and Java EE 6 Sun-Oracle roadshow - key notes<span style="font-size:130%;"><span style="font-weight: bold;">GlassFish Roadshow 2010 - London 03-02-2010</span><br /></span><br />The following is some notes I took down during the above event.<br /><br />In brief summary of GlassFish v3 and Java EE 6, here are some of the key takeaways:<br /><br /><ul><li>GlassFish v3 continues to be developed and supported, as the Java EE 5 & 6 RI app server</li><li>GlassFish v3 currently has no clustering, but offers OSGi modularization and extensibility</li><li>Supports and takes advantage of new Java EE 6 specifications</li><li>Big push on modularity and flexibility in both GlassFish and Java EE 6</li><li>Java EE 6 supports annotation based EJBs, RESTful web services</li><li>Java EE 6 greatly simplified configuration, optional web-inf.xml etc</li><li>Java EE 6 simplied simple class EJBs and improved JPA specification</li><li>Ongoing road-map for GlassFish, details TBA later this year<br /></li></ul><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Java EE 6 (Roberto</span><span style="visibility: visible; font-weight: bold;" id="main"><span style="visibility: visible;" id="search"> Chinnici</span></span><span style="font-weight: bold;">):</span><br /></span><br />Released Dec 10 2009<br /><br />Key new features: New API, Web profiles, Pluggabiliy, dependancy injection<br /><br /><span style="font-weight: bold;">New technologies:</span><br /><ul><li>Jax-RS 1.1</li><li>Bean validation 1.0</li><li>DI 1.0</li><li>CDI 1.0</li><li>Managed beans 1.0</li></ul>Closed down gap between EJB and POJO with unification and annotations<br /><br />CDI works with POJO and EJB classes<br /><br />Unification of platform types, more uniform programming model<br /><br /><ul><li>EJB 3.1</li><li>JPA 2.0</li><li>Servlet 3.0</li><li>JSF 2.0</li><li>Connectors 1.6</li><li>Interceptors 1.1</li><li>JAX-WS 2.2</li><li>JSR-109 1.3</li><li>JSP 2.2</li><li>JSR-250 1.1</li><li>JACC 1.4</li><li>JASPIC 1.1</li></ul><br />Key goal in Java EE 6 - flexibility, pruning, extensibility and web profiles<br /><br /><br /><span style="font-weight: bold;">Profiles:</span><br /><br /> Bundles of technologies targeting specific classes of applications<br /> Decoupled from each other and the platform<br /> Guarantees compatibility of required technologies, individually and in combination - must satisfy all joint requirements<br /><br /><br /><span style="font-weight: bold;">Web Profile:</span><br /><br />Modern Java web application stack<br />First profile to be definite<br />Mid sized, fully functional (expected 80% web-app coverage), add additional components via extensibility (such as web services API, 3rd party frameworks)<br /><br /><br /><span style="font-weight: bold;">Web profile contents:</span><br /><br />Servlet, JSP/EL, JSTL, JSF, Bean Validation, EJB Lite, JPA, JTA, Di, CDI, Managed beans, Interceptors, JSR-250<br /><br /><br /><span style="font-weight: bold;">Pruning:</span><br /><br />Goal - to address bloat concerns<br /><br />2 step process:<br /> Declare components as "Proposed optional"<br /> The make fully optional for the next release<br /><br />Proposed optional technologies:<br /><br /> JAX-RPC (JAX-WS)<br /> EJB 2.x Entity beans (JPA entity classes)<br /> JAXR (little use)<br /> JSR-88 (deployment, tools API - not used)<br /><br />* Don't use - use replacements / alternatives<br /><br /><br /><span style="font-weight: bold;">Pluggability / extensibility:</span><br /><br />Focus on web tier<br />Level playing field for 3-rd party libraries and frameworks<br />Two major extensibility points: Servlets and CDI<br />Simplify packaging of web-apps<br /> Zero-configuration!<br /><br /><br /><span style="font-weight: bold;">Modular Web applications:</span><br /><br />Libraries can contain web-fragment.xml descriptor<br />web.xml is now optional<br />Can server resources out of jars with: /META-INF/resources<br /><br />e.g.<br />/WEB-INF/lib/catalog.jar<br /> /META-INF/resources/catalog/books.html<br /><br />e.g. Dojo jar in resources<br /><br /><br /><span style="font-weight: bold;">Web fragments in servlet 3.0:</span><br /><br />META-INF.web-fragment.xml<br /><br />same structure as web.xml, can override in web.xml<br /><br /><br /><span style="font-weight: bold;">Servlet container pluggability:</span><br /><br />ServletContainerInitializer interface implements by extensions<br /><br />@HandlesTypes to declare interest in on or more annotation types<br /><br />ServletContext now contains method to dynamically register servlets and filters<br /> i.e. ServletContext API has been extended<br /><br />Registered using META-INF/services<br /><br /><br />onStartup method gets called with a Set of classes available<br /><br />** Can only add services at startup, not dynamically once running<br /><br /><br /><span style="font-weight: bold;">Asynchronous HTTP processing:</span><br /><br />New programming model for async request processing<br />e.g. Comet, char, push apps<br />Opt-in model<br />Threads are managed by the container<br /><br />@WebServlet(asyncSupported=true)<br />public class MyServlet extends HTTPServlet {<br /><br />}<br /><br />Goal - Decouple requests from threads<br /><br />* Changes to the way filters work - thread not attached to the socket, response not written. Filters modified to make safe - option than can be turned on to identify asyncSupported=true<br /> - do this on servlet and any filter involved in the chain<br /><br />Ideal when waiting for some external resource etc.<br /> Low level API - not very elegant<br /> Idea is that frameworks will use this - see for example Atmosphere framework which is based on annotations - under the hood this async API is used.<br /><br /><br /><span style="font-weight: bold;">JSF 2.0:</span><br /><br />Facelet as a standard view declaration language<br />Composite components<br />Ajax (declarative and programmatic) e.g. f:ajax tag<br />Partial state saving (track deltas and sends changes in response, previously all would have been sent even if not changed!)<br />System events e.g. f:event tag<br />Resources<br />Validation e.g. new f:validateBean tag (better integration, validation API. can handle multiple errors, not first one at a time!)<br /><br /><br /><span style="font-weight: bold;">EJB 3.1:</span><br /><br />@Singleton beans<br />@Startup beans (invoked at app startup, works well with Singleton pattern)<br />@Asynchronous invocations (biggest change, allows non-blocking sync EJB invocations as first class call. Method must be either void or return a Future object)<br />No interface view (bean impl does not need an interface anymore, now 1 class = 1 EJB!)<br />Define EJBs directly inside a web app, inside a war file<br />New API - EJBContainer API works on Java SE, can bootstrap an EJB container in a Java SE application (ideal for testing/development, could be useful in client applications)<br /><br /><br /><span style="font-weight: bold;">Simplified packaging:</span><br /><br />EJB class directly into the war file<br />Previously must built an EJB jar to be included<br /><br /><br /><span style="font-weight: bold;">EJB 3.1 lite:</span><br /><br />A subset of EJB 3.1<br />All types of session beans (stageful, stateless, singleton) - other bean types not supported (timer, entity etc)<br />Declarative transactions and security<br />Interceptors<br />ejb-jar.xml descriptor allows (is optional, probably not useful)<br /><br />* Class loading, new visibility rules in Java EE spec<br /><br />Slight differences in class loading rules - if in doubt check the specs<br /><br /><br /><span style="font-weight: bold;">New JNDI Namespaces:</span><br /><br />Until now - only java:comp<br />Now added:<br /> java:module - a module (war, ejb, jar)<br /> java:app - an application<br /> java:global the whole server / cluster<br /><br />e.g. @Resource(lookup="java:app/CustomerDB") DataSource db;<br /><br />EJB components have global names now:<br /><br />e.g. java:global/app1/module2/SomeBeanIcom.acme.Foo<br /><br />Helps solve problem of remote EJB communication in same app server<br /><br /><br /><span style="font-weight: bold;">Dependency injection (DI):</span><br /><br />Combination of DI 1.0 / CDI 1.0<br />New @Inject annotation<br />@Inject @LoggedIn User user; (@LoggedIn = "Which one", User = "What")<br />Beans auto-discovered at start-up<br />Extensible<br /> Injection metamodel (BeanManager API)<br />@Resource still available for container resources<br /><br />* Identified by type and qualifiers (no longer just a string name alone)<br /><br />* No bean declaration as per Spring declaration, bean discovery at startup<br />* Injection errors all reported at startup, rather than on use at runtime<br /><br />Beans can be associated with session - i.e. loggedIn<br />Beans can be more ephemeral, i.e. for request<br />Beans can be more long lived, i.e. shopping cart conversation flows<br />Can add class for beans on the fly, via APIs at runtime<br /><br />Example of DI annotation:<br /><br />@Inject<br />CheckoutHandler(<br /> @LoggedIn User user,<br /> @Reliable @PayBy(CREDIT_CARD)<br /> PaymentProcessor processor,<br /> @Default Cart cart)<br /><br />* Note that constructor injection is possible<br />* Note different scopes, PaymentProcessor is probably conversation scope, LoggedIn is session, PaymentProcessor is probably application scope singleton<br /><br />* Instance and state management handled "for free" by framework/APIs<br /><br /><span style="font-weight: bold;">JAX-RS 1.1:</span><br /> Already widely adoped<br />Really a high level HTTP API<br />Annotation-based programming model<br />Programmatic API when needed<br /><br />* think of it as the new HTTP level API (higher level than HTTPServlets, remove low level detail and tedium)<br /><br />Jax-RS resource class, example:<br /><br />Identified by the @Path annotation<br /><br />@Path("widgets./{id}")<br />@Produces("application/widgets+xml")<br />public class WidgetResource {<br /> pubic WidgetResource(@PathParam("id") String id { … }<br /> <br /> @GET<br /> Widget getWidget() { … }<br />}<br /><br />Provides higher level HTTP handling, more declarative, better match with conceptual needs of developer<br /><br /><br /><span style="font-weight: bold;">Bean Validation 1.0:</span><br /><br />Integrated with JSF, JPA<br />Constraints represented by annotations<br /><br />e.g.<br /><br /> @NotNull<br /> @Size(max=40)<br /> String address;<br /><br />Fully extensible<br /> @Email<br /> String recipient;<br /><br />Validation API's for validation directly, create a new validation object etc<br />Validation of trees of objects is possible (including loops)<br /><br /><br /><span style="font-weight: bold;">JPA 2.0:</span><br /><br />Supported for collections of basic types and embeddable objects<br />JPQL enhancements e.g. CASE WHEN, NULLIF<br />Pessimistic locking added (annotations added)<br />Criteria API for dynamic query construction<br /><br />Criteria API: Uses the canonical metamodel classes<br /><br />CriteriaBuilder, create criteria<br />CriterialQuery, typed criteria<br /><br />Strongly types checking, type parasitised equals checking, compiler errors generated if query does not have the right types etc, so robust and safe query (rather than say String SQL construction directly).<br /><br />Connectors 1.6 added too (not covered in any detail)<br /><br /><br /><span style="font-weight: bold;">Summary overview:</span><br /><br />Improved, more powerful, more flexible, more extensible, easier to use<br /><br /><a href="http://java.sun.com/javaee">http://java.sun.com/javaee</a><br /><br /><br />--<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">GlassFish V3 (Alexis Moussine-Pouchkine):</span></span><br /><br />Java EE 6 Reference Implementation (RI)<br /><br />Geographic download map:<br /><br /><a href="http://maps.glassfish.org/server">http://maps.glassfish.org/server</a><br /><br />Healthy increase in downloads and usage over time<br /><br />GlassFish V1 first shipped 2006, reusing much from Tomcat<br /><br />V2.1.1 Nov 2009, V3 (Java EE 6) Dec 10th 2009<br /><br />GlassFish V3 Open Source CDDL, GPL (with 'classpath exception') licensing<br /><br />Java EE 5 & 6, enterprise quality - full support is available.<br /><br />Sub projects:<br /><ul><li> Jersey (JAX-RS)</li><li> Metro (JAX-WS)</li><li> Grizzly (NIO)</li><li> Atmosphere (Comet)</li><li> OpenMQ (JMS)</li><li> and scripting jRoR Grails and now Django (python)</li></ul><br />Main difference from Tomcat - Grizzly core (rewritten)<br /><br />Netbeans 6.8 tooling<br />Support available in Eclipse too<br /><br />GlassFish development continues<br />Support contracts through to 2017+ unlimited<br />Remains the Java EE reference implementation<br />Now also sold with WebLogic and standalone<br /><br />Roadmap -> expected soon for remaining year<br /><br />Don't have to deliver as much standard runtime / frameworks jars as part of the application jar<br /><br />Netbeans in-place edit of classes, incremental compilation, deploy on save, GF v3 preserves session across redeployments(!)<br /><br />Session retention:<br /> Deployment option to maintain statefull sessions across re-deployments!<br /><br /><br /><span style="font-weight: bold;">GlassFish v3 key goals:</span><br /><br />Modular and dynamic<br /> Modular: Apache Felix (OSGi)<br /> Extensible: HK2 (100k kernel)<br /> Still very fast!<br /><br />Centralized configuration, modules configured through centralised control<br /><br /><br /><span style="font-weight: bold;">Key Features:</span><br /><br />No ejbjar.xml needed, no web.xml, annotation driven, EJB's as single classes<br /><br />Declarative annotations:<br /><br />@Stateless annotation for class stateless bean<br />@Schedule annotation for timers<br /><br />Eclipse - GlassFish tool bundle for eclipse (contains everything!)<br /><br />Ultra fast auto-deploy of all Java EE and static artefacts<br /><br />Maven support: mvn gf:run gf:start gf-deploy<br /><br />Containers can be added / removed dynamically<br /><br /><br /><span style="font-weight: bold;">New API for EJB testing (EJBContainer):</span><br /><br />Example:<br /><br />EJBContainer c = EJBContainer.createEJBContainer();<br />Context ice = c.getContext();<br />SimpleEjb ejb (SImpleEjb)ic.lookup("java:global/sample/SimpleEjb");<br />ejb.sayHello();<br /><br /><br />GlassFish "Embedded" - allows all features of GlassFish to be automated<br /><br />org.glassfish.api.embedded.Server server;<br />Server.Build builder = new Server.Builder();<br />server = builder.build();<br />ContainerBuilder b = server.createConfig(ContainerBuilder.Type.web);<br />server.addContainer(b);<br /><br />File archive = new File("hello.war");<br />server.getDeployer().deply(archive);<br /><br />i.e. Ship app server inside an application!<br /><br /><br /><span style="font-weight: bold;">OSGi:</span><br /><br />GlassFish runs on top of OSGi (Felix by default)<br /> Also runs unmodified on Knopflerfish and Equinox<br /> GlassFish ships with 200+ bundles<br /> Can run without OSGi (static mode based on HK2)<br /> Can use OSGi management tools (CLI or Web)<br /><br />Any OSGi bundles will run in GlassFish v3<br /> Drop it in glassfish/modules<br /><br />Servlets can get hold of OSGi bundles (using @Resource DI)<br /><br /><br /><span style="font-weight: bold;">Update centre:</span><br /><br />Graphical tool (GlassFish does not need to be started), available in web admin console<br />CLI version available<br />Was in v2.x but not from admin console<br /><br /><br /><span style="font-weight: bold;">RESTful admin API:</span><br /><br />JAX-RS/Jersey + Grizzly to provide REST interfaces to<br /> Configure runtime (via GET, POST, DELETE)<br /> Invoke commands (restart, stop, deploy, etc)<br /> Monitoring (GET only)<br /> Log rotation etc<br /> <br />e.g. Available from:<br /> localhost:4848/management/domain<br /> localhost:4848/monitoring/domain<br /><br /><br /><span style="font-weight: bold;">Further advantages:</span><br /><br />Dynamic language support via modules:<br /> Rails, Grails, Django, Scala/Lift<br /><br /><br /><span style="font-weight: bold;">Comet:</span><br /> Cometd/Bayeux<br /> Atmosphere<br /><br /><span style="font-weight: bold;">Full support for:</span><br /> mod_jk<br /> WebDAV, CGI, SSI<br /><br />OpenMQ 4.4<br /><br />Web Services Metro 1.4<br /> .NET 3.5 interoperability<br /><br /><br /><span style="font-weight: bold;">v3 Clustering:</span><br /> Lower priority after Java EE 6 and modularity, so not yet...<br /> Clustering is not built in as per v2<br /> More similar to v1, single instance<br /> Have to take on own clustering (load balancing, deployment)<br /> See roadmap for details...<br /><br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Doing More with GlassFish (Steve Elliott):</span></span><br /><br />GlassFish v3 - Management and monitoring<br /><br /><span style="font-weight: bold;">Management:</span><br /><br />User Friendly, pluggable and extensible for administration<br />Feature rich Admin console (GUI)<br />Easy to use Command Line Interface (CLI)<br />RESTful management and monitoring API<br />Fully documented AMX API (app server management API)<br />All management features built on AMX API<br /><br />OSGi, load on demand = fast initial start up<br /><br /><span style="font-weight: bold;">v3 AdminConsole:</span><br /> Frame-set removed, now Ajax based pages<br /> Pluggable console (admin panes, trees etc loaded on demand)<br /><br /><br /><span style="font-weight: bold;">Monitoring:</span><br /><br />Lightweight prode architecture<br />Ad hoc monitoring in Production<br />Client-scripting (JavaScript)<br />DTrace integration on Solaris (similar to OS probes, uniform tracing experience with MySQL etc)<br />Extensibility / Pluggability<br /><br />No overhead when there is no monitoring<br />Allows Monitoring to be turned on in a production environment with minimal impact<br />Generate and listen to only interested<br />Turn on monitoring when needed<br />BTrace integration<br /> Portable and dynamic<br /><br /><br /><span style="font-weight: bold;">Instrumentation:</span><br /><br />Modules expose probes<br /> POJO with annotations<br /> XML<br /><br />Modules register probe listeners<br /><br />In code, POJO annotations can be used<br /><br />@ProbeProvider(providername="glassfish", modulename="web")<br /><br />ProbeProvider XML configuration also possible<br /><br />ProbeListeners<br />JMX exposed<br /><br />@ManagedAttribute(id="jspcount")<br /><br /><br /><span style="font-weight: bold;">OSGi:</span><br /><br />big move to OSGi technology<br />Big move to more modular development approach<br /><br />Demands and enforces stronger modularity<br /><br />OSGi is largely under the covers<br /> Visible to GlassFish developers, but not to GlassFish users<br /><br /><br /><span style="font-weight: bold;">Service based architecture</span>:<br /><br /> Core modules loaded on app startup<br /> Rest loaded on demand<br /><br /><span style="font-weight: bold;">Module Management:</span><br /> add, remove, update installed modules<br /><br />OSGi as a container<br /><br /><br /><span style="font-weight: bold;">Web services - Metro : JAX-WS / Jersey : JAX-RS</span><br /><br />Metro - SOAP-based web services stack<br /> Built into GlassFish<br />Works with any servlet 2.5 compliant web container<br /> WebLogic, WebSphere, JBoss, Tomcat<br /> Also standalone<br />Advances interoperability with .NET 3.x/4.0<br /><br />Project Tango - focused on interoperability with .NET<br /><br />JAXB based XML Data Binding (XSD, XPATH)<br /><br />SOAP Messaging MTOM etc<br /><br />Bi-directional interoperability with .NET (Java or .NET as client or server)<br /><br /><br /><span style="font-weight: bold;">Standards:</span><br /><br />JCP: JAX-WS 2.2 & JAXB 2.2<br />W3C SPAP 1.1/1.2 WSDL 1.1, WS-Addressing<br />… etc<br /><br /><br /><span style="font-weight: bold;">JAX-RS</span>:<br /><br />JAX-RS 1.1 is final and part of EE6<br /><br />Not a web profile<br /> but included with GlassFish v3 web profile<br />JCP 311<br />Spec - JSR 311<br /><br /><a href="http://www.oracle.com/java">http://www.oracle.com/java</a><br />Contains links to GlassFish etc<br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-55064422927002113492009-11-01T11:52:00.001-08:002009-11-01T12:59:14.445-08:00Project Euler 12 - Scala Streams, creating triangle numbers<span style="font-weight: bold;">Just a short blog today on Scala Streams and generating numeric progressions, such as a simple arithmetic series</span><br /><br />This is a solution to project Euler problem 12: <a href="http://projecteuler.net/index.php?section=problems&id=12" style="text-decoration: none;" title="Click to view problem">"What is the value of the first triangle number to have over five hundred divisors?"</a><br /><br />This is actually a fairly easy problem to solve, providing you use a sufficiently efficient function to count the divisors!<br /><br />The method I've adopted for this is particularly simple, but performs sufficiently well to solve this problem as stated within a few seconds.<br /><br /><span style="font-weight:bold;">Triangle Numbers:<br /></span><br />Just a quick refresher, the triangle numbers are the sum of integers from 1 to n.<br /><br />An Arithmetic series is a number series of the form:<br /><br />a + (a + b) + (a + 2b) + ....<br /><br />and using this form the Triangle numbers can be written as:<br /><br /> 1 + (1 + 1) + (1 + 2) + (1 + 3) + ...<br /><br />so they clearly are of the form of an Arithmetic series.<br /><br /><br />The more interesting aspect of this problem was the generation of the Triangle number sequence. Naturally, wanting to use Scala to solve this problem, the idea of using a Stream to evaluate the triangle number sequence lazily on demand is a natural approach.<br /><br />The implementation I settled on to produce the Stream of triangle numbers was the iterative version as follows:<br /><br /><pre><br />val trianglesI = Stream.iterate((1L,0L)){<br /> case (n, sum) => (n + 1L, sum + n) }.map(_._2)<br /></pre><br /> <br />Which is a fairly natural way to solve via the additive definition of the triangle numbers.<br /><br />What's perhaps more interesting is finding some alternative ways to achieve the same thing, here are some alternatives to the iterative additive stream definition:<br /><br />Using the multiplicative definition of the Triangle numbers and the map function:<br /><br /><br /><pre><br />// use a stream map and the multiplicative solution for triangle numbers<br />val trianglesM = Stream.from(1).map(n => n * (n + 1) / 2)<br /> <br />println("trianglesM take(5)")<br />trianglesM.take(5).foreach(println)<br /></pre><br /><br /> <br />Using "inits" - inits are a concept that can be found in languages such as Haskell:<br /><br /><pre><br />// using inits (not efficient)<br />// inits -> inits(Stream.from(1)) is Stream(Stream(), Stream(1), Stream(1, 2), Stream(1, 2, 3), ...)<br />// and tails -> tails(Stream(1)) = Stream(Stream(1,2,3,...), Stream(2,3,4,...), Stream(3,4,5,...), ...)<br />def inits[T](xs: Stream[T]) = Stream.from(0).map(xs.take(_))<br /> <br />val trianglesInits = inits(Stream.from(1)).tail.map(_.sum)<br /><br />println("trianglesInits take(5)")<br />trianglesInits.take(5).foreach(println)<br /></pre><br /><br /><br />Using Stream.cons and a helper function zipWith that can zip tuples:<br /><br /><pre><br />// using zipWith<br />def zipWith[T1,T2,T3](s1: Stream[T1], s2: Stream[T2])(fn: (T1,T2) => T3) = <br /> s1.zip(s2).map(Function.tupled(fn))<br /> <br />lazy val trianglesZ: Stream[Int] = Stream.cons(1, zipWith(trianglesZ, <br /> Stream.from(2))(_ + _))<br /> <br />println("trianglesZ take(5)")<br />trianglesZ.take(5).foreach(println)<br /><br /></pre><br /><br /><br />So, whilst problem 12 is not too hard, the production of triangle numbers as lazy lists is quite interesting, being that there are several approaches that can be taken!<br /><br /><br />The whole program solution to problem 12 (and the alternative triangle number streams)<br /><br /><pre><br />package projecteuler<br /><br />object Problem12 {<br /><br /> def main(args : Array[String]) {<br /> <br /> println("result = " + problem12(500))<br /> }<br /> <br /> def problem12(target : Int) {<br /> <br /> // using Stream.iterate to create a lazy stream of triangle numbers<br /> val trianglesI = Stream.iterate((1L,0L)){ <br /> case (n, sum) => (n + 1L, sum + n) }.map(_._2)<br /> <br /> // test it<br /> //println("trianglesI take(5)")<br /> //trianglesI.take(5).foreach(println)<br /> <br /> // count the divisors (not massively efficient, but sufficient)<br /> def numDivisors(n : Long) = {<br /> <br /> var count = 0<br /> <br /> for (i <- 1L to Math.sqrt(n).toInt) {<br /> if (n % i == 0) {<br /> count = count + 2<br /> } <br /> }<br /> count<br /> }<br /> <br /> trianglesI.find(p => numDivisors(p) > target)<br /> }<br /> <br /> def otherTriangleStreams {<br /> <br /> // use a stream map and the multiplicative solution for triangle numbers<br /> val trianglesM = Stream.from(1).map(n => n * (n + 1) / 2)<br /> <br /> println("trianglesM take(5)")<br /> trianglesM.take(5).foreach(println)<br /> <br /> // using inits (not efficient)<br /> // inits -> inits(Stream.from(1)) is Stream(Stream(), Stream(1), Stream(1, 2), Stream(1, 2, 3), ...)<br /> // tails -> tails(Stream(1)) = Stream(Stream(1,2,3,...), Stream(2,3,4,...), Stream(3,4,5,...), ...)<br /> def inits[T](xs: Stream[T]) = Stream.from(0).map(xs.take(_))<br /> <br /> val trianglesInits = inits(Stream.from(1)).tail.map(_.sum)<br /> <br /> println("trianglesInits take(5)")<br /> trianglesInits.take(5).foreach(println)<br /> <br /> // using zipWith<br /> def zipWith[T1,T2,T3](s1: Stream[T1], s2: Stream[T2])(fn: (T1,T2) => T3) = s1.zip(s2).map(Function.tupled(fn))<br /> <br /> lazy val trianglesZ: Stream[Int] = Stream.cons(1, zipWith(trianglesZ, Stream.from(2))(_ + _))<br /> <br /> println("trianglesZ take(5)")<br /> trianglesZ.take(5).foreach(println)<br /> }<br />}<br /></pre><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1tag:blogger.com,1999:blog-89287579799971239.post-10747931106650600722009-09-27T09:31:00.000-07:002009-09-27T10:00:27.529-07:00Scala & GUIs, a simple maze generator and solver appletIn this blog we will touch on using <span style="font-weight: bold;">Scala</span> for a simple <span style="font-weight: bold;">GUI</span>, in the form of a simple <span style="font-weight: bold;">2D Maze Applet</span>.<br /><br />An example of this applet can be viewed running from here <a href="http://www.chillipower.com/examples/maze/maze1.html">http://www.chillipower.com/examples/maze/maze1.html</a> to give an illustration of what it does. This uses a maze space of 100x100 cells on a regular grid.<br /><br />The applet illustrates 2 aspects of GUI programming in Scala, the first is how to interact with basic javax.swing APIs directly and the second is how to go one step further and achieve the same effect using the scala.swing wrapper API instead.<br /><br />The function of the Applet can be broken down into 3 simple steps:<br /><br />Step 1: Produce a random maze. This uses a modified version of Prim's algorithm, running backwards from the exit until all of the available space has been covered. This will produce a simple path from the source to the exit, which is the path we seek when we try to solve the maze by starting at the start. The standard Prim's algorithm is used to produce a minimum spanning tree from a directed acyclic graph by recursively adding safe edges to the current minimum spanning tree recursively, starting at a source node.<br /><br />Step 2: Use a regular (recursive) DFS algorithm to search the maze, stopping only when the exit is reached (or all paths are explored fully if there were no reachable exit).<br /><br />Step 3: Remove all backtrack paths and show the single simple path from start to exit as the solution to the maze.<br /><br />During maze exploration, the parts of the maze explored are marked with coloured breadcrumbs, red indicates a forward search path and blue a backtracking path (which happens when a path reaches a dead-end).<br /><br />In step 2, in order to stop immediately when the exit is found (rather than conclude all other possible search branches) the recursive maze solving function throws an exception to escape out of the call stack immediately.<br /><br />The code given is compatible with the very latest Scala 2.8.x trunk development builds, and with 2.7.6 the latest stable release (some 2.7.6 only versions of functions such as shuffle are commented out in preference to the newer and better 2.8 versions). Note that there are currently some issues with Arrays in 2.8.x causing run time errors with trying to create a multidimensional array. The solution that still works with current 2.8 builds is to use the Array.tabulate function.<br /><br />i.e. the following works in 2.7.6 but not currently in 2.8:<br /><br /><span style="font-family:courier new;">var cells : Array[Array[Cell]] = new Array[Array[Cell]](WIDTH, HEIGHT)</span><br /><br />and there are similar problems with the new Array.ofDims function too. These issues should be resolved in 2.8 final release but recently arrays in scala have been undergoing some re-factoring and so stability in this area has not been too strong.<br /><br />One interesting thing to note is the use of the new Scala 2.8+ Stream.iterate function to avoid undesirable vars instead of vals, here is an example of that extracted from the code.<br /><br />A typical iterative piece of code, the while loops is used to iterate over some code block whilst a particular condition is met for a given variable. For this to work the variable n needs to be updated in the loop, hence it can't be a val and has to be a var instead. This is somewhat paradigmatic of iterative imperative programming, but doesn't sit well with the strive for a more functional style.<br /><br /><pre><br />var n = cells(exit.x)(exit.y)<br /><br />while (n != null) {<br /><br /> n.trail = Forward<br /> n = n.pi<br /> update<br />}<br /></pre><br /><br /><br />What we can do here is make use of the Stream.iterate function to avoid the unsightly var n, as follows:<br /><br /><br /><pre><br />Stream.iterate(cells(exit.x)(exit.y))(_.pi).takeWhile(_ != null).foreach{<br /> n => {<br /> n.trail = Forward<br /> update<br /> }<br />}<br /></pre><br /><br />Given that this is new in Scala 2.8 and 2.8 isn't released yet, you can augment existing 2.7.6 code with a helper function to aid the transition and improve 2.7 based code in readiness for 2.8. Here is an example of a util class that defines iterate so the same idea can be used in 2.7 based code:<br /><br /><pre><br />def iterate[T](x:T)(f : T => T) : Stream[T] =<br /> Stream.cons(x, iterate(f(x))(f))<br /></pre><br /><br /><br />Another interesting thing to note in the code is the use of a permutation on a list (to create random directions when generating or exploring the maze), here is the code:<br /><br /><pre><br />def shuffle[T](xs: List[T], r: scala.util.Random) = {<br /> xs.toStream.zip(Stream.const(r.nextDouble _).map(_())).toList.sort(_._2 < _._2).map(_._1)<br />}<br /></pre><br /><br /><span style="font-family:arial;">The code maps the elements with a stream of random real numbers and then permutes by sorting the list, extracting the sorted items to create the random permutation (neat huh!)</span><br /><br /><span style="font-family:arial;">The above code is 2.7.x & 2.8+ compatible, but perhaps even better is the following 2.8+ code that makes use of the new Stream.continually function:</span><br /><br /><pre><br />def shuffle[T](xs: List[T])(implicit r: scala.util.Random) = {<br /> xs.zip(Stream.continually(r.nextDouble)).sortWith(_._2 < _._2).map(_._1)<br />}<br /></pre><br /><br /><span style="font-family:arial;">In terms of the GUI aspects, the application is an applet, and the example code shows 2 ways of achieving this in Scala. The first, using the swing API directly is as follows:</span><br /><br /><pre><br />class MazeApplet2 extends JApplet {<br /><br /> override def init() {<br /> ...<br /> }<br /><br /> override def start() {<br /> }<br />}<br /></pre><br /><br /><br /><span style="font-family:arial;">Which is familiar to any Java programmer, but the more interesting approach is using the scala.swing API instead, whereby we have:</span><br /><br /><br /><pre><br />class MazeApplet extends Applet {<br /><br /> object ui extends UI with Reactor {<br /><br /> def init() = {<br /> ...<br /> }<br /><br /> override def start() = {<br /> }<br /> }<br />}<br /></pre><br /><br /><br /><span style="font-family:arial;">Where the abstract ui attribute (of type UI) is implemented using the Reactor </span><span style="font-style: italic;font-family:arial;" >mixin</span><span style="font-family:arial;"> </span><span style="font-style: italic;font-family:arial;" >trait</span><span style="font-family:arial;"> (</span><a href="http://www.scala-lang.org/docu/files/api/scala/swing/Reactor.html"><span style="font-family:courier new;">http://www.scala-lang.org/docu/files/api/scala/swing/Reactor.html</span></a><span style="font-family:arial;">), to provide the framework for event handling.</span><br /><br /><span style="font-family:arial;">One thing that's quite clear is the obviously similarity between the function to generate and the function to solve the maze. Using the DSL-like features of Scala it should be possible to extract the common control structure / algorithm and create a new utility function to provide built-in like support for this, passing in a body function to provide the difference implementation of maze generate vs. solve.</span><br /><br /><br /><span style="font-weight: bold;font-family:arial;" >Full code example:</span><br /><br /><br /><pre><br />/**<br />* Scala 2.8+ Maze Applet v0.1 20-09-2009 Louis Botterill<br />*/<br />package maze<br /><br />import scala.swing.Applet<br />import scala.swing.Panel<br />import scala.swing.Reactor<br /><br />import javax.swing._;<br />import java.awt.Graphics;<br />import java.awt.Color;<br /><br /><br />object Direction extends Enumeration {<br /> type Direction = Value<br /> val North, South, East, West = Value<br />}<br /><br />object Breadcrumb extends Enumeration {<br /> type Breadcrumb = Value<br /> val Forward, Backward, Clear = Value<br />}<br /><br />import Direction._<br />import Breadcrumb._<br /><br />class MazeModel {<br /> val HEIGHT = 100<br /> val WIDTH = 100<br /><br /> // instantiate and initialise the 2d array - there is a direct 2d version but not working currently in scala 2.8.x<br /> var cells = Array.tabulate(WIDTH)(i => Array.tabulate(HEIGHT)(j => Cell(i, j)))<br /><br /> // set everything as not visited and with no trail<br /> def clearVisited() = {<br /><br /> cells.foreach(_.foreach(c => {<br /> c.visited = false;<br /> c.trail = Clear<br /> }))<br /> }<br /><br /> // generate maze<br /> def generateMaze(update : => Unit) {<br /><br /> val exit = new Point(WIDTH - 1, HEIGHT - 1)<br /> val start = new Point(0, 0)<br /><br /> // 1. Start at a particular cell, call it the "exit"<br /> // 2. Mark the current cell as visited, and get a list of all its neighbors.<br /> // For each neighbor, starting with a randomly selected neighbor:<br /> // 1. If that neighbor hasn't been visited,<br /> // remove the wall between this cell and that neighbor,<br /> // and then recurse with that neighbor as the current cell.<br /><br /> // cell 0,0 is the start, open the north wall to highlight this<br /> var s = cells(0)(0)<br /> s.clear(North);<br /><br /> // cell width-1,height-1 is the exit, open the south wall to highlight this<br /> val c = cells(exit.x)(exit.y)<br /> c.clear(South);<br /><br /> // recursively process the next cell<br /> def doNextCell(c : Cell) {<br /><br /> c.visited = true<br /> c.trail = Forward<br /><br /> var dirs = c.getRndDirections()<br /><br /> while (!(dirs isEmpty)) {<br /> val dir = dirs.head<br /> val x = getCell(c, dir)<br /><br /> x match {<br /> case Some(n) =><br /> <br /> if (n.visited != true) {<br /> n.visited = true<br /> c.clear(dir)<br /> n.clear(getInv(dir))<br /> n.trail = Forward<br /> update<br /> doNextCell(n)<br /> n.trail = Clear<br /> update<br /> }<br /><br /> case None =><br /> }<br /><br /> dirs = dirs.tail<br /><br /> //Thread.sleep(1)<br /> }<br /> }<br /><br /> doNextCell(c)<br /> }<br /><br /> // find the maze solution using dfs from the start node until the end<br /> // node is located<br /> def solveMaze(update : => Unit) {<br /> <br /> val start = new Point(0, 0)<br /> val exit = new Point(WIDTH - 1, HEIGHT - 1)<br /><br /> val s = cells(0)(0)<br /> s.clear(North);<br /><br /> def doNextCell(c : Cell) {<br /><br /> c.visited = true<br /> c.trail = Forward<br /><br /> var dirs = c.getDirections()<br /> <br /> while (!(dirs isEmpty)) {<br /> val dir = dirs.head<br /> val x = getCell(c, dir)<br /><br /> x match {<br /> case Some(n) =><br /><br /> if (n.visited != true) {<br /> n.visited = true<br /> n.pi = c // set predecessor node<br /> n.trail = Forward<br /> update<br /> if (n.i == exit.x && n.j == exit.y) throw new Exception("Done")<br /> doNextCell(n)<br /> n.trail = Backward<br /> update<br /> }<br /><br /> case _ =><br /> }<br /><br /> // take the top item off and use the rest of the list<br /> dirs = dirs.tail<br /> <br /> Thread.sleep(1) // add a little delay so we can watch the dfs explore and find the solution<br /> }<br /> }<br /><br /> doNextCell(s)<br /> }<br /><br /> // from the exit recurse over the trail of predecessors,<br /> // marking with a forward trail<br /> def showSolution(update : => Unit) {<br /><br /> val exit = new Point(WIDTH - 1, HEIGHT - 1)<br /><br /> // 2.8 avoid var using Stream<br /> // Stream.iterate(cells(exit.x)(exit.y))(_.pi).takeWhile(_ != null)<br /> Stream.iterate(cells(exit.x)(exit.y))(_.pi).takeWhile(_ != null).foreach{<br /> n => {<br /> n.trail = Forward<br /> update<br /> }<br /> }<br /><br /> // the following works fine but replaced with the above to avoid unnecessary var<br /> /*<br /> var n = cells(exit.x)(exit.y)<br /><br /> while (n != null) {<br /><br /> n.trail = Forward<br /> n = n.pi<br /> update<br /> }<br /> */<br /> }<br /><br /> // get the cell if possible based on current cell and the given direction<br /> def getCell(c : Cell, dir : Direction) : Option[Cell] = dir match {<br /><br /> case North => if (c.j > 0) Some(cells(c.i)(c.j-1)) else None<br /> case South => if (c.j < east =""> if (c.i < west =""> if (c.i > 0) Some(cells(c.i-1)(c.j)) else None<br /> }<br /><br /> // find the inverse direction for a given direction<br /> def getInv(dir : Direction) = dir match {<br /><br /> case North => Direction.South<br /> case South => Direction.North<br /> case East => Direction.West<br /> case West => Direction.East<br /> }<br />}<br /><br />// a scala.swing.Panel, override paint(Graphics2D) to paint each of the cells<br />class MazePanel(m : MazeModel) extends Panel {<br /><br /> override def paint(g : java.awt.Graphics2D) {<br /><br /> m.cells.foreach(_.foreach(_.draw(g)))<br /> }<br />}<br /><br />// a javax.swing.JPanel, override paint(Graphics) to paint each of the cells<br />class MazePanel2(m : MazeModel) extends JPanel {<br /><br /> override def paint(g : Graphics) {<br /><br /> m.cells.foreach(_.foreach(_.draw(g)))<br /> }<br />}<br /><br />// a scala.swing.Applet based applet using scala swing wrappers<br />class MazeApplet extends Applet {<br /> val m = new MazeModel()<br /> lazy val mp = new MazePanel(m)<br /><br /> object ui extends UI with Reactor {<br /><br /> def init() = {<br /> contents = mp<br /> }<br /><br /> override def start() = {<br /> def update = {<br /> this.repaint()<br /> }<br /><br /> m.generateMaze(update)<br /><br /> Thread.sleep(2000)<br /><br /> m.clearVisited<br /><br /> try {<br /> m.solveMaze(update);<br /> }<br /> catch {<br /> case e : Exception =><br /> }<br /><br /> Thread.sleep(2000)<br /><br /> m.clearVisited<br /><br /> m.showSolution(update)<br /><br /> mp.repaint()<br /> this.repaint()<br /> }<br /> }<br />}<br /><br />// standard javax.swing.JApplet of the maze<br />class MazeApplet2 extends JApplet {<br /><br /> val m = new MazeModel()<br /> lazy val mp = new MazePanel2(m)<br /><br /> def MazeApplet2 = {<br /> }<br /><br /> override def init() {<br /><br /> this.add(mp)<br /> }<br /><br /> override def start() {<br /> def update = {<br /> this.repaint()<br /> }<br /> <br /> m.generateMaze(update)<br /><br /> Thread.sleep(2000)<br /><br /> m.clearVisited<br /><br /> try {<br /> m.solveMaze(update);<br /> }<br /> catch {<br /> case e : Exception =><br /> }<br /><br /> Thread.sleep(2000)<br /><br /> m.clearVisited<br /><br /> m.showSolution(update)<br /><br /> mp.repaint()<br /> this.invalidate()<br /> this.repaint()<br /> }<br /><br /> override def stop() {<br /> }<br /><br /> override def destroy() {<br /> }<br />}<br /><br />// standard Java app of the maze using JFrame<br />object Maze {<br /><br /> def main(args: Array[String]) {<br /><br /> val mazeApplet = new MazeApplet()<br /> val frame = new JFrame()<br /> frame.setBounds(50, 50, 750, 750)<br /> frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);<br /><br /> frame.add(mazeApplet)<br /><br /> frame.setVisible(true)<br /> mazeApplet.init<br /> mazeApplet.start<br /> }<br />}<br /><br />// represent a Cell of the maze<br />case class Cell(i: Int, j : Int) {<br /><br /> val size = 7; // each cell is 7px by 7px<br /> var north : Boolean = true<br /> var south : Boolean = true<br /> var east : Boolean = true<br /> var west : Boolean = true<br /> var visited : Boolean = false<br /> var pi : Cell = null // predecessor cell<br /> var trail : Breadcrumb = Clear;<br /><br /> def draw(g : Graphics) {<br /><br /> val x = i * size<br /> val y = j * size<br /><br /> trail match {<br /> case Forward => {<br /> g.setColor(Color.RED);<br /> g.fillRect(x + 2, y + 2, size - 4, size - 4)<br /> }<br /> case Backward => {<br /> g.setColor(Color.BLUE);<br /> g.fillRect(x + 2, y + 2, size - 4, size - 4)<br /> }<br /> case _ =><br /> }<br /><br /> g.setColor(Color.BLACK);<br /> if (north) {<br /> g.drawLine(x, y, x + size, y);<br /> }<br /> if (south) {<br /> g.drawLine(x, y + size, x + size, y + size);<br /> }<br /> if (east) {<br /> g.drawLine(x + size, y, x + size, y + size);<br /> }<br /> if (west) {<br /> g.drawLine(x, y, x, y + size);<br /> }<br /> }<br /><br /> def clear(dir : Direction) = dir match {<br /><br /> case North => north = false<br /> case South => south = false<br /> case East => east = false<br /> case West => west = false<br /> }<br /><br /> def getDirections() : scala.List[Direction] = {<br /><br /> var d = scala.List[Direction]()<br /><br /> if (!north) d = North :: d<br /> if (!south) d = South :: d<br /> if (!east) d = East :: d<br /> if (!west) d = West :: d<br /><br /> d<br /> }<br /><br /> def getRndDirections() : scala.List[Direction] = {<br /><br /> val directions = North :: South :: East :: West :: Nil<br /> implicit val r = Rand.rand<br /> Utils.shuffle(directions) //, Rand.rand)<br /> }<br />}<br /><br />// represent a 2d point<br />case class Point(x : Int, y : Int)<br /><br />// init a random generator singleton<br />object Rand {<br /> val rand : scala.util.Random = new scala.util.Random();<br />}<br /><br />object Utils {<br /><br /> // ref: http://okmij.org/ftp/Haskell/perfect-shuffle.txt<br /> // scala 2.7+ here's an O(n log n) solution:<br /> /*<br /> def shuffle[T](xs: List[T], r: scala.util.Random) = {<br /> xs.toStream.zip(Stream.const(r.nextDouble _).map(_())).toList.sort(_._2 < nil =""> scala.List(Nil)<br /> case _ => xs.flatMap(x => permute(xs.filter(_ != x)).map(x :: _))<br /> }<br /><br /> // make a stream of x, f(x), f(f(x)), etc.<br /> // in Haskell this is called "iterate". it ought to be in the standard library<br /> // as Stream.iterate. "unfold" should be more general, but nonetheless I'm<br /> // going to call this unfold for the moment...<br /> def unfold[T](x:T)(f:T=>T):Stream[T] =<br /> Stream.cons(x,unfold(f(x))(f))<br /><br /> def iterate[T](x:T)(f:T=>T):Stream[T] =<br /> Stream.cons(x,iterate(f(x))(f))<br />}<br /></pre><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-28511726864885092912009-08-31T11:31:00.000-07:002009-08-31T12:24:27.922-07:00Scala, trees, pattern matching and tree recursionHi! Long time no see...<br /><br />Well after some outage due to Holiday (road trip around Europe and down to the Swiss Alps!), work commitments and some personal things to deal with, I'm back again.<br /><br />I thought I'd start with some stuff on Tree structures, whilst continuing on with Scala too. The following code illustrates some good examples of case classes and pattern matching, along with extensive use of Some, None and Option (Scala's improved way of dealing with optional types, rather than relying on null everywhere).<br /><br />The following code defines a simple recursive binary tree definition as a case class, using option to define the left and right children.<br /><pre><br />case class Tree[+T](value: T, left: Option[Tree[T]], right: Option[Tree[T]])<br /></pre>The above definition defines a tree recursively, exactly as a tree is defined as a data structure in computer science. Each tree node has a value of type T and an Optional left and right child node (bin tree). The +T makes the Tree type covarient about T, which is a generally useful property of a Tree.<br /><br />A few helper functions are used that make life a little easier when working with Option types, by extracting the value or providing a safe default when no value exists. These help keep the code a little tidy and manageable.<br /><br /><pre><br /> /**<br /> * Helper function: For o return f: A => Int if Some or 0 if None<br /> * also could try opt map f getOrElse 0<br /> */<br /> def zeroIfNone[A](o: Option[A], f: A => Int): Int = o match {<br /> case None => 0<br /> case Some(x) => f(x)<br /> }<br /><br /> /**<br /> * Helper function: Return value of function provided if Some, or 0 otherwise<br /> */<br /> def zeroIfNoneVal[A](o: Option[A], n: => Int) = zeroIfNone[A](o, _ => n)<br /><br /> /**<br /> * Helper function: Default to provided value if option is None<br /> */<br /> def defaultIfNone[A](o: Option[A], f: A => Int, d : Int): Int = o match {<br /> case None => d<br /> case Some(x) => f(x)<br /> }<br /></pre><br /><br />The example code demonstrates preorder, inorder and postorder recursive tree traversal (which are all simple permutations of a basic depth first search), applying the provided unit function to each node as it is visited.<br /><br />Recall that the preorder, inorder and postorder functions are defined as follows:<br /><br /><ul><li>PreOrder - visit parent node, left and then right child node</li><li>InOrder - visit left, parent and then right nodes</li><li>PostOrder - visit left, right and then parent node</li></ul><br /><br />Using recursion and the call stack, depth first search based tree traversal is very simple and concise. The basic DFS inorder traversal looks like:<br /><br /><pre><br /> /**<br /> * Perform an inorder tree traversal using the provided Tree[A] => Unit function<br /> */<br /> def inOrder[A](t: Option[Tree[A]], f: Tree[A] => Unit) : Unit = t match {<br /><br /> case None =><br /> case Some(x) =><br /> if (x.left != None) inOrder(x.left, f)<br /> f(x)<br /> if (x.right != None) inOrder(x.right, f)<br /> }<br /></pre><br /><br />The breadth first search algorithm is perhaps more interesting. This uses a List as a basic FIFO queue to provide the breadth first search tree traversal:<br /><br /><pre><br /> /**<br /> * Breadth first search on a tree, a list is used as a basic fifo queue to<br /> * give the bfs traversal<br /> */<br /> def breadthFirstSearch[A](t: Tree[A], f: Tree[A] => Unit): Unit = {<br /> def bfs(ts: List[Tree[A]]): Unit = ts match {<br /> case Nil => // ignore<br /> case _ =><br /> val children = for{tree <- ts <br /> Some(child) <- List(tree.left, tree.right)} <br /> yield child <br /> ts map f <br /> bfs(children) <br /> } <br /> bfs(List(t)) <br /> } </pre><br /><br />The example also shows a treeFold function. Whether this is a useful function as-is is perhaps debatable, but it makes for an interesting example. The code traverses the tree in a DFS inorder traversal and applies the mapping function f : A -> B and then it applies the join function j : B, B -> B to combine the results of the tree map. In this way the function is similar to say flatMap where a list is mapped and then flattened into a single list, or perhaps more closely to foldLeft/foldRight where items in a list a joined into a single resulting value.<br /><br /><br /><pre><br /> /**<br /> * Fold up a tree into a single value, using provided map and join functions<br /> */<br /> def treeFold[A, B](t: Option[Tree[A]],<br /> f: Option[Tree[A]] => Option[B],<br /> j: (Option[B], Option[B]) => Option[B]) : Option[B] = t match {<br /><br /> case None => None<br /> case Some(x) => j(j(f(t), treeFold(x.left, f, j)), treeFold(x.right, f, j))<br /> }<br /></pre><br /><br />Some utility functions are also defined, to return the size and depth of the tree for illustration of how this can be achieved.<br /><br />In summary Scala can quite elegantly represent Tree data structures, using case classes and operate over them using pattern matching and higher order functions to provide powerful and concise support for trees and the operations that can be performed on them.<br /><br />Some additional things that could be done here would be to provide an example of a binary search and perhaps insertion, update and delete too. A job for another followup blog perhaps...<br /><br /><br />The full example code (is complete and self contained) is as follows:<br /><br /><pre><br />package trees<br /><br />// Define a recursive Bin Tree structure<br />case class Tree[+T](value: T, left: Option[Tree[T]], right: Option[Tree[T]])<br /><br />object TreeObj {<br /><br /> /**<br /> * Helper function: For o return f: A => Int if Some or 0 if None<br /> * also could try opt map f getOrElse 0<br /> */<br /> def zeroIfNone[A](o: Option[A], f: A => Int): Int = o match {<br /> case None => 0<br /> case Some(x) => f(x)<br /> }<br /><br /> /**<br /> * Helper function: Return value of function provided if Some, or 0 otherwise<br /> */<br /> def zeroIfNoneVal[A](o: Option[A], n: => Int) = zeroIfNone[A](o, _ => n)<br /><br /> /**<br /> * Helper function: Default to provided value if option is None<br /> */<br /> def defaultIfNone[A](o: Option[A], f: A => Int, d : Int): Int = o match {<br /> case None => d<br /> case Some(x) => f(x)<br /> }<br /><br /> /**<br /> * Return the size of the tree<br /> */<br /> def size[A](t : Option[Tree[A]]) : Int = t match {<br /><br /> case None => 0<br /> case Some(x) =><br /> zeroIfNoneVal(x.left, size(x.left)) + zeroIfNoneVal(x.right, size(x.right)) + 1<br /> //zeroIfNone(x.left, (_:Tree[Any]) => (size(x.left))) +<br /> //zeroIfNone(x.right, (_:Tree[Any]) => (size(x.right))) + 1<br /> }<br /><br /> /**<br /> * Alternative size using nested function<br /> */<br /> def size2[A](t : Option[Tree[A]]) : Int = {<br /><br /> def sizeB(b : Option[Tree[A]]) : Int = b match {<br /> case None => 0<br /> case Some(x) => size(b);<br /> }<br /><br /> t match {<br /> case None => 0<br /> case Some(x) =><br /> sizeB(x.left) + sizeB(x.right) + 1<br /> }<br /> }<br /><br /> /**<br /> * Return the max depth of the tree<br /> */<br /> def depth[A](t : Option[Tree[A]]) : Int = t match {<br /><br /> case None => 0<br /> case Some(x) =><br /> Math.max(zeroIfNoneVal(x.left, depth(x.left)), zeroIfNoneVal(x.right, depth(x.right))) + 1<br /> }<br /><br /> /**<br /> * Alternative deptch, return the max depth of the tree using nested function<br /> */<br /> def depth2[A](t : Option[Tree[A]]) : Int = {<br /><br /> def depthB(b : Option[Tree[A]]) : Int = b match {<br /> case None => 0<br /> case Some(x) => depth(b);<br /> }<br /><br /> t match {<br /><br /> case None => 0<br /> case Some(x) =><br /> Math.max(depthB(x.left), depthB(x.right)) + 1<br /> }<br /> }<br /><br /> /**<br /> * Breadth first search on a tree, a list is used as a basic fifo queue to<br /> * give the bfs traversal<br /> */<br /> def breadthFirstSearch[A](t: Tree[A], f: Tree[A] => Unit): Unit = {<br /> def bfs(ts: List[Tree[A]]): Unit = ts match {<br /> case Nil => // ignore<br /> case _ =><br /> val children = for{tree <- ts Some(child) <- List(tree.left, tree.right)} yield child ts map f bfs(children) } bfs(List(t)) } /** * Sum up the elements of a numeric tree */ def sumTree[A <: Int](t: Option[Tree[A]]) : Int = t match { case None => 0<br /> case Some(x) =><br /> sumTree(x.left) + sumTree(x.right) + x.value<br /> }<br /><br /> /**<br /> * Fold up a tree into a single value, using provided map and join functions<br /> */<br /> def treeFold[A, B](t: Option[Tree[A]],<br /> f: Option[Tree[A]] => Option[B],<br /> j: (Option[B], Option[B]) => Option[B]) : Option[B] = t match {<br /><br /> case None => None<br /> case Some(x) => j(j(f(t), treeFold(x.left, f, j)), treeFold(x.right, f, j))<br /> }<br /><br /> /**<br /> * Perform an inorder tree traversal using the provided Tree[A] => Unit function<br /> */<br /> def inOrder[A](t: Option[Tree[A]], f: Tree[A] => Unit) : Unit = t match {<br /><br /> case None =><br /> case Some(x) =><br /> if (x.left != None) inOrder(x.left, f)<br /> f(x)<br /> if (x.right != None) inOrder(x.right, f)<br /> }<br /><br /> /**<br /> * Perform a preorder tree traversal using the provided Tree[A] => Unit functio<br /> */<br /> def preOrder[A](t: Option[Tree[A]], f: Tree[A] => Unit) : Unit = t match {<br /><br /> case None =><br /> case Some(x) =><br /> f(x)<br /> if (x.left != None) inOrder(x.left, f)<br /> if (x.right != None) inOrder(x.right, f)<br /> }<br /><br /> /**<br /> * Perform a postorder tree traversal using the provided Tree[A] => Unit functio<br /> */<br /> def postOrder[A](t: Option[Tree[A]], f: Tree[A] => Unit) : Unit = t match {<br /><br /> case None =><br /> case Some(x) =><br /> if (x.left != None) inOrder(x.left, f)<br /> if (x.right != None) inOrder(x.right, f)<br /> f(x)<br /> }<br /><br /> /**<br /> * build tree and run tree functions on it<br /> */<br /> def main(args : Array[String]) {<br /><br /> /* Test Tree structure<br /><br /> 1<br /> / \<br /> 2 3<br /> / \ / \<br /> 4 x 5 6<br /> <br /> */<br /><br /> // build a tree<br /> val myTree = Tree(1,<br /> Some(Tree(2,<br /> Some(Tree(4, None, None)),<br /> None<br /> )<br /> ),<br /> Some(Tree(3,<br /> Some(Tree(5, None, None)),<br /> Some(Tree(6, None, None))<br /> )<br /> )<br /> )<br /><br /> printBfsTree(myTree)<br /><br /> println("Size = " + size(Some(myTree)))<br /><br /> println("Depth = " + depth(Some(myTree)))<br /><br /> println("Sum = " + sumTree(Some(myTree)))<br /> <br /> var sum = treeFold[Int, Int](<br /> Some(myTree),<br /> (t: Option[Tree[Int]]) => t match { case None => Some(0); case Some(x) => Some(x.value) },<br /> (x: Option[Int], y: Option[Int]) =><br /> Some(zeroIfNone[Int](x, (x:Int) => x) + zeroIfNone[Int](y, y => y))<br /> )<br /><br /> var mult = treeFold[Int, Int](<br /> Some(myTree),<br /> (t: Option[Tree[Int]]) => t match { case None => Some(0); case Some(x) => Some(x.value) },<br /> (x: Option[Int], y: Option[Int]) =><br /> Some(defaultIfNone[Int](x, (x:Int) => x, 1) * defaultIfNone[Int](y, y => y, 1))<br /> )<br /><br /> println("Sum Result = " + sum)<br /> println("Mult Result = " + mult)<br /><br /> println("InOrder = ")<br /> inOrder(Some(myTree), (t: Tree[Any]) => println(t.value))<br /><br /> println("PreOrder = ")<br /> preOrder(Some(myTree), (t: Tree[Any]) => println(t.value))<br /><br /> println("PostOrder = ")<br /> postOrder(Some(myTree), (t: Tree[Any]) => println(t.value))<br /> }<br /><br /> /**<br /> * Print a tree using BFS, passing in print unit function<br /> */<br /> def printBfsTree[A](tree: Tree[A]) {<br /><br /> breadthFirstSearch(tree, (t: Tree[A]) => println(t.value))<br /> }<br />}<br /></pre><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1tag:blogger.com,1999:blog-89287579799971239.post-79880326012577706752009-07-09T11:01:00.000-07:002009-10-16T13:45:51.961-07:00Notes on Adobe LiveCycle, Flash, Flex and AirHaving recently attended <span style="font-style: italic;"><span style="font-weight: bold;">Adobe LiveCycle</span></span> training at Adobe Uxbridge, here are a few notes and links from it.<br /><br />Adobe LiveCycle is an integrated Java based SOA and document management server framework. LiveCycle can be hosted on a JEE application server, including JBoss, WebSphere and WebLogic. LiveCycle requires a Database, mySql, Oracle and MS SQL are supported.<br /><br />LiveCycle is offers best performance on Microsoft/MS SQLServer platforms - currently.<br /><br />LiveCycle is compatible with Windows, Solaris, AIX and Linux<br /><br />LiveCycle is designed to integrate with RIA technologies, such as Flash, Flex and Air.<br /><br /><br /><span style="font-weight: bold;">Key LiveCycle features include:</span><br /><br /><ul><li>Forms builder - a PDF based form generation engine for PDF/HTML and Flash presentation</li><li>Form Guides - based on PDF but with wizard style Flash presentation</li><li>Reader/Reader extensions - Acrobat/Reader document management including digital signatures, revocation, permissions etc</li><li>Process Management</li><li>Data Services - Web Services, support for RESTful webservices in the next version</li><li>Output - print/production services</li></ul><br /><br /><ul><li>Flash is the original rich embedded content for multimedia, video, graphics and sound - flash runs as a plugin in the browser (although stand alone players are available too).</li><li>Flex builds on Flash and adds a rich component model.</li><li>Air is Flex technology that can be run in the browser or as desktop applications transparently.</li></ul><br />LiveCycle and Flex based technologies can use ActionScript, a form of ECMA (JavaScript), Flex itself uses an XML format called mxml to define applications and component layout.<br /><br /><br /><span style="font-weight: bold;">Key Tools:</span><br /><br /><ul><li><span style="font-weight: bold; font-style: italic;">FlexBuilder</span> - IDE for Flex/Air development</li><li><span style="font-weight: bold; font-style: italic;">LiveCycle Workbench</span> - for LiveCycle development including forms and process management</li></ul><br /><br />Main Development WebSite: <a href="http://www.adobe.com/devnet/">http://www.adobe.com/devnet/</a><br />Main Download home: <a href="http://www.adobe.com/downloads/">http://www.adobe.com/downloads/</a><br />Flex Downloads: <a href="http://www.adobe.com/products/flex/flexdownloads/">http://www.adobe.com/products/flex/flexdownloads/</a><br /><br />Flex Development center: <a href="http://www.adobe.com/devnet/flex/?view=home">http://www.adobe.com/devnet/flex/?view=home</a><br />TourDeFlex: <a href="http://www.adobe.com/devnet/flex/tourdeflex/">http://www.adobe.com/devnet/flex/tourdeflex/</a><br />TourDeLiveLycle: <a href="http://www.adobe.com/devnet/livecycle/tourdelivecycle/">http://www.adobe.com/devnet/livecycle/tourdelivecycle/</a><br />LiveCycle Cafe: <a href="http://www.adobe.com/devnet/livecycle/cafe/">http://www.adobe.com/devnet/livecycle/cafe/</a><br /><br />LiveDocs (online documentation): <a href="http://livedocs.adobe.com/">http://livedocs.adobe.com/</a><br />ActionScript 3: <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/">http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/</a><br />Flex 3 LiveDocs: <a href="http://livedocs.adobe.com/flex/3/">http://livedocs.adobe.com/flex/3/</a><br /><br />Adobe Partners: <a href="https://www.adobe.com/cfusion/partnerportal/index.cfm">https://www.adobe.com/cfusion/partnerportal/index.cfm</a><br /><br />FlashDevelop: Getting started <a href="http://nuigroup.com/forums/viewthread/1689/">http://nuigroup.com/forums/viewthread/1689/</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1tag:blogger.com,1999:blog-89287579799971239.post-48857690434746344872009-07-05T12:35:00.000-07:002009-07-09T13:03:18.813-07:00Scala, the Google App Engine and an iPhone client...In this Blog I wanted to explore <span style="font-weight: bold; font-style: italic;">Scala</span> on the <span style="font-weight: bold; font-style: italic;">Google App Engine</span>. The Google App Engine has supported Java (as well as Python) for a little while now. There have been a few blogs about running Scala on the App engine and I wanted to further demonstrate this by taking a simple Java Servlet and converting it to a Scala based web application suitable for the App Engine.<br /><br />The Google App Engine home is here <a href="http://code.google.com/appengine/">http://code.google.com/appengine/</a> and contains excellent documentation on how to get stated. I don't want to repeat the documentation, so I'll just point out the essentials relevant to this blog.<br /><br />The Getting Started guide can be found here: <a href="http://code.google.com/appengine/docs/java/gettingstarted/">http://code.google.com/appengine/docs/java/gettingstarted/</a> for Java, and a Python equivalent is available too.<br /><br />This example is based on the previous blog, the Sieve of Eratosthenes as a simple prime number generator. The request accepts one parameter n whose integer value is the upper limit to generate all the primes until (from 2). The response output is <span style="font-weight: bold;">JSON</span> encoded to create a simple web service.<br /><br /><br />Starting with the very basics, the recommended project directory structure is of the form:<br /><br /><pre><br />|-src<br />|---META-INF<br />|---primes<br />|-war<br />|---WEB-INF<br />|-----classes<br />|-------META-INF<br />|-------primes<br />|-----lib<br /></pre><br /><br /><br />For any Web App for the Google App Engine, one additional GAE specific file is required alongside the standard <span style="font-style: italic; font-weight: bold;">web.xml </span>deployment descriptor. This file is called <span style="font-weight: bold; font-style: italic;">appengine-web.xml</span> and contains the name of the Application, for example:<br /><br /><pre><br /><appengine-web-app xmlns="http://appengine.google.com/ns/1.0"><br /> <application>primes-chillipower-com</application><br /> <version>1</version><br /></appengine-web-app><br /></pre><br /><br />In this simple GAE deployment descriptor the main thing is that the name of the application is specified, in this example the application was called 'primes-chillipower-com'.<br /><br />Applications must be created on the App Engine, this can be done here: <a href="http://appengine.google.com/">http://appengine.google.com/</a><br /><br />Note that there are some limitations currently, you are allowed up to a maximum of 10 applications and applications can not be deleted once created!<br /><br /><br /><span style="font-weight: bold;">The simple Java version:</span><br /><br />In the simple Java version we can place a simple Servlet in the src directory and build using ant.<br /><br /><br /><span style="font-weight: bold;">Example Java servlet:</span><br /><br /><pre><br />package primes;<br /><br />import java.io.IOException;<br />import javax.servlet.http.*;<br /><br />public class PrimesServletJ extends HttpServlet {<br />public void doGet(HttpServletRequest req, HttpServletResponse resp)<br /> throws IOException {<br /> resp.setContentType("text/plain");<br /><br />int n = 100;<br /><br />String nStr = req.getParameter("n");<br /><br />try {<br /><br /> n = Integer.parseInt(nStr);<br />}<br />catch (Exception e) {}<br /><br />int[] primes = primes(n);<br /><br />resp.getWriter().println("{ \"n\" : \"" + n + "\",");<br />resp.getWriter().println(" \"primes\" : [ ");<br /><br />for (int i = 0; i < primes.length; i++) {<br /> String sep = (i < primes.length - 1) ? ", " : "";<br /> resp.getWriter().println(" { \"" + i + "\" : \"" + primes[i] + "\" }" + sep);<br /> }<br /><br />resp.getWriter().println(" ] }");<br />}<br /><br />public static int[] primes(int n) {<br /><br /> // initially assume all integers are prime<br /> boolean[] isPrime = new boolean[n + 1];<br /><br /> for (int i = 2; i <= n; i++) {<br /> isPrime[i] = true;<br /> }<br /><br /> // mark non-primes <= N using Sieve of Eratosthenes<br /> for (int i = 2; i*i <= n; i++) {<br /><br /> // if i is prime, then mark multiples of i as nonprime<br /> // suffices to consider mutiples i, i+1, ..., N/i<br /> if (isPrime[i]) {<br /> for (int j = i; i * j <= n; j++) {<br /> isPrime[i * j] = false;<br /> }<br /> }<br /> }<br /><br /> // count primes<br /> int primeCount = 0;<br /> for (int i = 2; i <= n; i++) {<br /> if (isPrime[i]) primeCount++;<br /> }<br /><br /> System.out.println("The number of primes <= " + n + " is " + primeCount);<br /><br /> int[] primes = new int[primeCount];<br /> int idx = 0;<br /> for (int i = 0; i <= n; i++) {<br /> if (isPrime[i] == true) {<br /><br /> primes[idx] = i;<br /> idx++;<br /> }<br /> }<br /><br /> return primes;<br />}<br /><br />public static void main(String[] args) {<br /><br /> int n = 100;<br /><br /> if (args.length > 0 && args[0] != null) {<br /> n = Integer.parseInt(args[0]);<br /> }<br /><br /> int[] primes = primes(n);<br /><br /> for (int p : primes) {<br /> System.out.println("Prime: " + p);<br /> }<br />}<br />}<br /></pre><br /><br /><br />The ant build script goes in the root of the project, to start with I based mine on the example on the Google App Engine documentation here <a href="http://code.google.com/appengine/docs/java/tools/ant.html#Uploading_and_Other_AppCfg_Tasks">http://code.google.com/appengine/docs/java/tools/ant.html#Uploading_and_Other_AppCfg_Tasks</a><br /><br />Using the standard ant script the project can be compiled and even run locally using the SDK.<br /><br /><span style="font-family:courier new;">ant compile</span><br /><br /><span style="font-family:courier new;">ant runserver</span><br /><br /><br />If you start the dev app server locally, it will be accessibly using a URL of the form:<br /><br /><a href="http://localhost:8080/yourappcontextpath"><span style="font-family:courier new;">http://localhost:8080/yourappcontextpath</span><br /></a><br /><br />Where the port 8080 is the default and can be changed in the script.<br /><br />The App Engine SDK comes with <span style="font-weight: bold; font-style: italic;">appcfg.sh</span> script in the bin directory, which can be used to perform operations such as uploading your app to the App Engine.<br /><br /><br /><span style="font-family:courier new;">../../../../tools/appengine-java-sdk-1.2.1/bin/appcfg.sh update war</span><br /><br /><br /><span style="font-weight: bold;">The Scala version:</span><br /><br />The main tasks in converting this conventional Java Servlet based web app to a Scala based one is to:<br /><ul><li>Rewrite the Java Servlet in Scala.</li><li>Reconfigure the ant build.xml to modify the classpath to include the Scala libraries and to run the Scala scalac compiler to create the Java .class files from the .scala source files.</li></ul><br />Since the Servlet API is a Java based API, there will of course be some reference to Java based classes in the Scala Servlet.<br /><br /><br /><span style="font-weight: bold;">Example Scala based Servlet:</span><br /><br /><pre><br />package primes<br /><br />import javax.servlet.http._<br /><br /><br />class PrimesServlet extends HttpServlet {<br />override def doGet(request: HttpServletRequest, response: HttpServletResponse) = {<br /><br /> var n = 100<br /><br /> try {<br /> val nStr = request.getParameter("n"); <br /> n = Integer.parseInt(nStr);<br /> } catch {<br /> case e : Exception => {<br /> println("Exception e " + e.getMessage())<br /> }<br /> }<br /><br /> val ps = primes take n<br /> val out = response.getWriter()<br /><br /> out.println("{ \"n\" : \"" + n + "\", \"primes\" : [")<br /><br /> var i = 0<br /> for (p <- ps) {<br /> val sep = if (i < ps.length - 1) ", " else ""<br /> out.println(" { \"" + i + "\" : \"" + p + "\" }" + sep)<br /> i = i + 1<br /> }<br /><br /> out.println(" ] } ")<br />}<br /><br />def primes = {<br /> def sieve(is: Stream[Int]): Stream[Int] = {<br /> val h = is.head<br /> Stream.cons(h, sieve(is filter (_ % h > 0)))<br /> }<br /><br /> sieve(Stream.from(2))<br />}<br />}<br /><br /><br /></pre><br /><br /><br /><span style="font-weight: bold;">Example modified and build.xml file:</span><br /><br /><pre><br /><project><br /><property name="scala.home" location="/Users/chillipower_uk/dev/tools/scala/scala-2.7.5.final/" /><br /><property name="sdk.dir" location="/Users/chillipower_uk/dev/tools/appengine-java-sdk-1.2.1/" /><br /><br /><import file="${sdk.dir}/config/user/ant-macros.xml" /><br /><br /><path id="project.classpath"><br /><pathelement path="war/WEB-INF/classes" /><br /><fileset dir="war/WEB-INF/lib"><br /> <include name="**/*.jar" /><br /></fileset><br /><fileset dir="${sdk.dir}/lib"><br /> <include name="shared/**/*.jar" /><br /></fileset><br /></path><br /><br /><!-- Copy over Scala jars --><br /><target name="init"><br /><property<br /> name="scala-library.jar"<br /> value="${scala.home}/lib/scala-library.jar"<br /> /><br /><path id="build.classpath"><br /> <pathelement location="${scala-library.jar}" /><br /><br /> <pathelement location="${build.dir}" /><br /></path><br /><taskdef resource="scala/tools/ant/antlib.xml"><br /> <classpath><br /> <pathelement location="${scala.home}/lib/scala-compiler.jar" /><br /> <pathelement location="${scala-library.jar}" /><br /> </classpath><br /></taskdef><br /></target><br /><br /><!-- Copy Scala JARs --><br /><target name="copyscala"<br /> description="Copies the Scala JARs to the WAR."><br /><copy<br /> todir="war/WEB-INF/lib"<br /> flatten="true"><br /> <fileset dir="${scala.home}/lib"><br /> <include name="**/scala-library.jar" /><br /> </fileset><br /></copy><br /></target><br /><br /><!-- Copy App engine jars --><br /><target name="copyjars"<br /> description="Copies the App Engine JARs to the WAR."><br /><copy<br /> todir="war/WEB-INF/lib"<br /> flatten="true"><br /> <fileset dir="${sdk.dir}/lib/user"><br /> <include name="**/*.jar" /><br /> </fileset><br /></copy><br /></target><br /><br /><target name="compile" depends="copyscala, copyjars, init"<br /> description="Compiles Java source and copies other source files to the WAR."><br /><mkdir dir="war/WEB-INF/classes" /><br /><copy todir="war/WEB-INF/classes"><br /> <fileset dir="src"><br /> <exclude name="**/*.scala" /><br /><exclude name="**/*.java" /><br /> </fileset><br /></copy><br /><scalac<br /> srcdir="src"<br /> destdir="war/WEB-INF/classes"<br /> classpathref="project.classpath"<br /> /><br /><br /><!--<br /><copy todir="war/WEB-INF/classes"><br /> <fileset dir="src"><br /> <exclude name="**/*.scala" /><br /> <exclude name="**/*.java" /><br /> </fileset><br /></copy> --><br /><javac<br /> srcdir="src"<br /> destdir="war/WEB-INF/classes"<br /> classpathref="project.classpath"<br /> debug="on" /><br /><br /></target><br /><br /><target name="datanucleusenhance" depends="compile"<br /> description="Performs JDO enhancement on compiled data classes."><br /><enhance_war war="war" /><br /></target><br /><br /><target name="runserver" depends="datanucleusenhance"<br /> description="Starts the development server."><br /><dev_appserver war="war" /><br /></target><br /><br /><target name="update" depends="datanucleusenhance"<br /> description="Uploads the application to App Engine."><br /><appcfg action="update" war="war" /><br /></target><br /><br /><target name="update_indexes" depends="datanucleusenhance"<br /> description="Uploads just the datastore index configuration to App Engine."><br /><appcfg action="update_indexes" war="war" /><br /></target><br /><br /><target name="rollback" depends="datanucleusenhance"<br /> description="Rolls back an interrupted application update."><br /><appcfg action="rollback" war="war" /><br /></target><br /><br /><target name="request_logs"<br /> description="Downloads log data from App Engine for the application."><br /><appcfg action="request_logs" war="war"><br /> <options><br /> <arg value="--num_days=5"/><br /> </options><br /> <args><br /> <arg value="logs.txt"/><br /> </args><br /></appcfg><br /></target><br /><br /></project><br /><br /></pre><br /><br /><br /><span style="font-weight: bold;">Example request and output:</span><br /><br />Request: <a href="http://primes-chillipower-com.appspot.com/primes?n=50">http://primes-chillipower-com.appspot.com/primes?n=50</a><br /><br /><pre><br />{ "n" : "50", "primes" : [ { "0" : "2" }, { "1" : "3" }, { "2" : "5" }, { "3" : "7" }, { "4" : "11" }, { "5" : "13" }, { "6" : "17" }, { "7" : "19" }, { "8" : "23" }, { "9" : "29" }, { "10" : "31" }, { "11" : "37" }, { "12" : "41" }, { "13" : "43" }, { "14" : "47" }, { "15" : "53" }, { "16" : "59" }, { "17" : "61" }, { "18" : "67" }, { "19" : "71" }, { "20" : "73" }, { "21" : "79" }, { "22" : "83" }, { "23" : "89" }, { "24" : "97" }, { "25" : "101" }, { "26" : "103" }, { "27" : "107" }, { "28" : "109" }, { "29" : "113" }, { "30" : "127" }, { "31" : "131" }, { "32" : "137" }, { "33" : "139" }, { "34" : "149" }, { "35" : "151" }, { "36" : "157" }, { "37" : "163" }, { "38" : "167" }, { "39" : "173" }, { "40" : "179" }, { "41" : "181" }, { "42" : "191" }, { "43" : "193" }, { "44" : "197" }, { "45" : "199" }, { "46" : "211" }, { "47" : "223" }, { "48" : "227" }, { "49" : "229" } ] }<br /></pre><br /><br /><br /><span style="font-weight: bold;">The iPhone client:</span><br /><br />I'm currently developing using the iPhone 3.1 beta SDK. I'm not going to post all the source code the the simple client, but rather give some essential snippets relevant to the invocation of the simple JSON web service once deployed on the Google App Engine.<br /><br />To Consume this JSON in an iPhone app, we can use the JSON Objective-C library, which is available on Google code here <a href="http://code.google.com/p/json-framework/wiki/FAQ">http://code.google.com/p/json-framework/wiki/FAQ</a><br /><br /><br /><pre><br />- (void)loadData {<br />[super viewDidLoad];<br /><br />NSString *urlString = [NSString stringWithFormat:@"http://primes-chillipower-com.appspot.com/primes?n=1000"];<br />NSURL *url = [NSURL URLWithString:urlString];<br /><br />NSDictionary *primesResponse = (NSDictionary *)[JsonClientHelper fetchJSONValueForURL:url];<br /><br />if (primesResponse != nil) {<br /><br />NSArray *primeEntries = [primesResponse objectForKey:@"primes"];<br /><br />NSMutableArray *primesTemp = [[NSMutableArray alloc] init];<br />[primesTemp retain];<br /><br />for (int i = 0; i < [primeEntries count]; i++) {<br /><br /> NSDictionary *primeEntry = (NSDictionary*)[primeEntries objectAtIndex:i];<br /><br /> NSString *key = [NSString stringWithFormat:@"%d", i];<br /><br /> NSString *p = [primeEntry objectForKey:key];<br /><br /> NSString *msg = [NSString stringWithFormat:@"Prime %d = %@", i, p];<br /><br /> NSLog(msg);<br /><br /> [primesTemp addObject:p];<br />}<br /><br />primes = [primesTemp copy];<br /><br />[primesTemp release];<br />}<br />}<br /><br /></pre><br /><br /><br />The above code makes a request to the JSON web service on the App Engine and decodes the response, which once decoded using the JSON library is contained in Dictionaries (NSDictionary) and Arrays (NSArray).<br /><br /><br />Where JsonClientHelper contains a basic class helper method fetchJSONValueForURL to fetch and decode a JSON response from the supplied URL.<br /><br /><br /><pre><br />+ (id)fetchJSONValueForURL:(NSURL *)url<br />{<br />NSString *jsonString = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];<br /><br />id jsonValue = [jsonString JSONValue];<br /><br />[jsonString release];<br /><br />return jsonValue;<br />}<br /></pre><br />I hope this Blog has helped give some insight into creating a Scala based Web Application for the Google App Engine, as well as the consumption of JSON in an iPhone Objective-C client.<br /><br />(I appologise for the formatting of the code in this blog, finding it awkward to get the code into the blog without it being mangled in some way!).<br /><br /><br /><span style="font-weight: bold;">Resources:</span><br /><br />Handy JSON Lint tool: <a href="http://www.jsonlint.com/">http://www.jsonlint.com/</a><br /><br />Scala Servlet development: <a href="http://blogs.oracle.com/aseembajaj/2008/08/scala_servlet_development.html">http://blogs.oracle.com/aseembajaj/2008/08/scala_servlet_development.html</a><br /><br />Scala on the Google App Engine: <a href="http://froth-and-java.blogspot.com/2009/04/scala-on-google-appengine.html">http://froth-and-java.blogspot.com/2009/04/scala-on-google-appengine.html</a><br /><br />The Google App Engine provides support for JPA and JDO based persistence - a comparison of the two can be found here: <a href="http://www.jpox.org/docs/persistence_technology.html">http://www.jpox.org/docs/persistence_technology.html</a> Further details of the JDO specification can be found here: <a href="http://java.sun.com/jdo/index.jsp">http://java.sun.com/jdo/index.jsp</a> and the JDO specification here: <a href="http://java.sun.com/javaee/technologies/persistence.jsp">http://java.sun.com/javaee/technologies/persistence.jsp</a><br /><br />Support for the Google App Engine in Netbeans: <a href="http://kenai.com/projects/nbappengine/pages/Home">http://kenai.com/projects/nbappengine/pages/Home</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-33619303949698189992009-07-03T10:52:00.000-07:002009-10-16T13:34:44.376-07:00Scala, lazy evaluation and the Sieve of EratosthenesThis blog posting is primarily concerned with looking at <span style="font-style: italic; font-weight: bold;">lazy evaluation</span> in functional programing, what it means and how it can be put to use.<br /><br />Lazy evaluation can be described as an expression that has a value, but that is not evaluated until it's actually needed. Conversely strict refers to the opposite property where all expressions are evaluated up front when declared.<br /><br />Some functional languages are described as Pure Lazy (no, this is not a derogatory term!), to reflect the fact that all evaluation is performed on demand. Haskell is on such language. Scala has both aspects of strict evaluation and lazy evaluation, as such it couldn't be referred to as 'pure' in either sense.<br /><br />By means of the simplest example I can think of to illustrate Lazy evaluation, consider the following interaction with the Scala CLI:<br /><br /><pre><br />scala> lazy val a = b + 1; lazy val b = 1;<br />a: Int = <lazy><br />b: Int = <lazy><br /><br />scala> a<br />res9: Int = 2<br /><br />scala> b<br />res10: Int = 1<br /></pre><br /><br />I think this illustrates lazy evaluation, without defining the 'vals' as lazy the statement lazy val a = b + 1; lazy val b = 1; as val a = b + 1; val b = 1; couldn't be evaluated because b would be undefined when evaluating a!<br /><br />The examples are based on the <span style="font-weight: bold;">Sieve of Eratosthenes</span>. Eratosthenes was an ancient Greek Mathmetician from 276 BC<sup id="cite_ref-0" class="reference"><a href="http://en.wikipedia.org/wiki/Eratosthenes#cite_note-0"><span></span><span></span></a></sup> – c. 195 BC.<span style="text-decoration: underline;"> </span><a href="http://en.wikipedia.org/wiki/Eratosthenes#cite_note-1"><span></span></a>The Sieve of Eratosthenes is a ancient algorithm for finding prime numbers from 2 .. n. Stated simply, this algorithm can be expressed as:<br /><br /><br /><ul><li>Create a list of all the numbers from 2 .. n.</li><li>Starting at p = 2</li><li>Strike out all multiples of p up until n from the list</li><li>Let p now be the first (lowest) number that has not been struck-off the list</li><li>Repeat the last two steps until p^2 > n</li><li>All remaining numbers not struck from the list are prime</li></ul><br />In Haskell this can be expressed very elegantly and succinctly, as follows:<br /><br /><span style="font-family:courier new;">primes = sieve [2..]</span><br /><span style="font-family:courier new;">sieve (p : xs) = p : sieve [x | x <− xs, x `mod` p > 0]</span><br /><br /><br />Note that [2..] creates an infinite steam of all the integers from 2 to infinity. You might think this is impossible and would create an out of memory error on the machine it ran on, but this is perfectly valid in a pure lazy language because none of the numbers are actually generated until they are requested!<br /><br />In Scala there's not really a way to represent this quite so succinctly, but it is possibly to create a Lazy stream of numbers using:<br /><br /><span style="font-family:courier new;">var is = Stream from 2</span><br /><br />which is essentially equivalent to Haskell's:<br /><br />[2..]<br /><br />Syntax.<br /><br /><br />Another important thing to note and be aware of is that Scala's List class is not a lazy list. Therefore, trying to make the equivalent of the Haskell algorithm in Scala using a List is not going to work.<br /><br />Scala's Stream class however is Lazy, and so it can form the basic of the equivalent algorithm in Scala. To be specific, Scala's Stream class is strict about head and lazy about tail - which is ok since head contains a finite set of 0|1 elements.<br /><br /><br />The following Scala code shows two ways to implement the Sieve using Scala Lazy streams.<br /><br /><br /><span style="font-weight: bold;">Example 1:</span><br /><br /><pre><br />package primes;<br /><br />/* Haskell...<br /><br />primes = sieve [2..]<br />sieve (p : xs) = p : sieve [x | x <− xs, x `mod` p > 0]<br />*/<br />object Primes1 {<br /><br />def primes : Stream[Int] = {<br /><br /> var is = Stream from 2<br /><br /> def sieve(numbers: Stream[Int]): Stream[Int] = {<br /> Stream.cons(<br /> numbers.head,<br /> sieve(for (x <- numbers.tail if x % numbers.head > 0) yield x))<br /> }<br /><br /> sieve(is)<br />}<br /><br />def main(args : Array[String]) = {<br /><br /> primes take 100 foreach println<br />}<br />}<br /><br />object Primes2 {<br />def primes = {<br /> def sieve(is: Stream[Int]): Stream[Int] = {<br /> val h = is.head<br /> Stream.cons(h, sieve(is filter (_ % h > 0)))<br /> }<br /><br /> sieve(Stream.from(2))<br />}<br /><br />def main(args: Array[String]) {<br /> println(primes take 100 toList)<br />}<br />}<br /><br /></pre><br /><br />Note the use of the 'take' method to extract the first 100 primes from the stream (so the program terminates!).<br /><br /><br />This second example shows how we can define a Lazy list like trait and then use it to implement the same, equivalent behavior:<br /><br /><br /><span style="font-weight: bold;">Example 2:</span><br /><br /><pre><br />package primes<br /><br /><br />object PrimesLazyTrait {<br /><br />sealed trait Lazy[+A] {<br /> def head: A = this match {<br /> case Nil => error("head called on empty")<br /> case Cons(h, _) => h()<br /> }<br /><br /> def tail: Lazy[A] = this match {<br /> case Nil => error("tail on empty")<br /> case Cons(_, t) => t()<br /> }<br /><br /> def filter(p: A => Boolean): Lazy[A] = this match {<br /> case Nil => Nil<br /> case Cons(h, t) => if(p(h())) Cons(h, () => t() filter p) else t() filter p<br /> }<br /><br /> def foreach(f: A => Unit) {<br /> this match {<br /> case Nil =><br /> case Cons(h, t) => {<br /> f(h())<br /> t() foreach f<br /> }<br /> }<br /> }<br /><br /> def toList: List[A] = this match {<br /> case Nil => scala.Nil<br /> case Cons(h, t) => h() :: t().toList<br /> }<br />}<br /><br />final case class Cons[+A](h: () => A, t: () => Lazy[A]) extends Lazy[A]<br />case object Nil extends Lazy[Nothing]<br /><br />def from(n: Int): Lazy[Int] = Cons(() => n, () => from(n + 1))<br /><br />def primes = {<br /> def sieve(is: => Lazy[Int]): Lazy[Int] = {<br /> lazy val h = is.head<br /> Cons(() => h, () => sieve(is filter (_ % h > 0)))<br /> }<br /><br /> sieve(from(2))<br />}<br /><br />def main(args: Array[String]) {<br /> primes foreach println<br />}<br />}<br /><br /></pre><br /><br /><br />In this version we see the Lazy trait provides the necessary methods head, tail, filter, foreach and toList.<br /><br /><br />These little examples help demonstrate some of the power, elegance and conciseness of lazy functional programming - as well as the beauty of this Ancient Greek algorithm for finding primes.<br /><br /><br />The basic algorithms complexity is:<br /><br /><ul><li>O((nlogn)(loglogn)) </li></ul><br />And has a memory requirement of:<br /><br /><ul><li>O(n).</li></ul><br />Without any optimization.<br /><br />--<br /><br /><span style="font-weight: bold;">Additional example - e (Euler's number): </span><br /><br />Calculating e, a list of converging numbers in the sequence of e<br /><br /><span style="font-weight: bold;">e</span> can be defined as <span style="font-weight: bold;">lim n->inf ( 1 + 1/n)^n </span>and therefore expressed directly as a function e of n as follows:<br /><br /><span style="font-family: courier new;">def e(n : Int) = { Math.pow((1.0 + (1.0/n)), n) }</span><br /><br />So, how can we turn this into a stream? If we create a stream of numbers from 1 that are mapped using the e function, which can be defined as an anon lambda argument to map:<br /><br /><span style="font-family: courier new;">val es = Stream.from(1).map((n => { Math.pow((1.0 + (1.0/n)), n) }))</span><br /><br />Example usage of the e stream:<br /><br /><span style="font-family: courier new;">es take 5 toList</span><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com5tag:blogger.com,1999:blog-89287579799971239.post-63597824058052907892009-06-15T14:10:00.000-07:002009-06-17T14:12:48.729-07:00Scala actors, an introduction with some simple examplesThe Scala programming language provides an Actor based framework for handling concurrency.<br /><br />Scala's Actor model for concurrent programming was originally inspired by the Erlang programming language.<br /><br />The actor model is a system of asynchronous message passing for concurrent programming, rather than the typical shared data and locks model. The shared data and locks model has some inherent difficulties that make programming in this way difficult and error prone. Major problems with shared data and locks include the well known dead-lock problem, as well as live locks and the general problem of locking shared mutable data without affecting program scalability and performance. Whilst Scala's actor messaging framework is build around asynchronous messaging, synchronous messaging is provided on top of this for convenience.<br /><br />The Scala's actor model is based around an actor library and the Actor trait, along with some simple syntactical constructs for sending and receiving messages.<br /><br />The actor library can be included into a project using:<br /><br /><pre>import scala.actors.Actor._</pre><br />The simplest way to start an actor is to declare an object/class that extends the class Actor and in the body of the actor declare an act() {} method to do the work. The actor x can then be started much like a thread, using x.start(). The act() method is much like the Java Thread's run() method.<br /><br />A more succinct method is to declare a variable val x = actor {} and put the action definition directly between the braces (no act method required). What happens here is that actor is a helper method on Actor that creates and starts the actor - so there is no need to call x.start() explicitly when using this approach.<br /><br />Actors can receive messages using the receive {} method. The receive message is passed a partial function to receive the messages. Typically the body of the receive method uses case pattern matching to determine what to do with the message.<br /><br />A message can be sent to an actor using the ! operation. For example, an Int can be sent to actor x using: x ! 3<br /><br />All actors get their own thread to call the receive function - this causes scalability problems when there are many actors with receive functions. The way to overcome this in Scala is to use the react() {} method instead. React is similar to receive except it doesn't not need a native thread to run and but must call itself when done to receive more messages - apart from this both are the same in that they both take a partial function.<br /><br />Scala provides a convenience to avoid having to call act/react within a react method, this is the loop construct. This ends up looking as simple as:<br /><br /><pre><br />loop {<br /> react {<br /> // message handling body goes here<br /> }<br />}<br /></pre><br />Note that react itself does not end end by returning up the call stack in the normal way, all calls to react result in an exception.<br /><br />Within a receive or react method, an actor can reply to the sender of the received message by messaging the special identifier "sender", which represents the source of the message.<br /><br /><br /><span style="font-weight: bold;">Example 1:</span><br /><br />This simple example shows the most basic way to create an actor, by extending Actor, creating an instance and calling start on it.<br /><br /><pre><br />package scalaactors1<br /><br />import scala.actors._<br /><br />class Actor1 extends Actor {<br /><br /> def act {<br /> var x = 1<br /> while (true) {<br /> println("actor1! " + x)<br /> x = x + 1<br /> Thread.sleep(500)<br /> }<br /> }<br />}<br /><br />object TestActors1 {<br /><br /> /**<br /> * @param args the command line arguments<br /> */<br /> def main(args: Array[String]) = {<br /><br /> println(">>main() - starting")<br /><br /> val actor1 = new Actor1()<br /><br /> actor1.start()<br /><br /> println("<<main() - ending")<br /> }<br />}<br /></pre><br /><br /><br /><span style="font-weight: bold;">Example 2:</span><br /><br />This example creates a couple of actors using the val x = actor {} constructs. Each actor will automatically start and run concurrently, outputting a message and sleeping in an infinite loop. If you run this you can observe that the main thread starts and ends, the messages from the two actors are interleaved and run even after the main method has ended.<br /><br /><pre><br />package scalaactors1<br /><br />import scala.actors.Actor._<br /><br />object TestActors2 {<br /><br /> /**<br /> * @param args the command line arguments<br /> */<br /> def main(args: Array[String]) = {<br /><br /> println(">>main() - starting")<br /><br /> <br /> val actor1 = actor {<br /><br /> var x = 1<br /> while (true) {<br /> println("actor1! " + x)<br /> x = x + 1<br /> Thread.sleep(500)<br /> }<br /> }<br /><br /> val actor2 = actor {<br /><br /> var x = 1<br /> while (true) {<br /> println("actor2! " + x)<br /> x = x + 1<br /> Thread.sleep(1000)<br /> }<br /> }<br /><br /> println("<<main() - ending")<br /> }<br />}<br /></pre><br /><br /><br /><span style="font-weight: bold;">Example 3:</span><br /><br />This example is slightly more complex.<br /><br />Actor kbReaderActor takes input from the keyboard (as Chars) and passes them one by one to the actor kbProcessorActor which prints out the received character and then uses a 3rd actor called sleep to sleep for the specified amount of time before then waking up the kbProcessorActor (to simulate some "work" that takes a finite amount of time to complete). Note that sleep signals the "sender" using a simple case class to represent the message type (with no arguments).<br /><br /><br /><pre><br />package scalaactors1<br /><br />import scala.actors.Actor._<br /><br />case class Wakeup // simple signalling case class<br /><br /><br />// simple actor example<br />object TestActors3 {<br /><br /> def main(args: Array[String]) = {<br /><br /> println(">>Starting")<br /><br /> val sleep = actor {<br /><br /> loop {<br /> react {<br /> case x : int => {<br /> println("sleeping for " + x)<br /> <br /> java.lang.Thread.sleep(x)<br /><br /> println("waking up sender...")<br /><br /> sender ! Wakeup<br /> }<br /> }<br /> }<br /> }<br /><br /> val keyProcessorActor = actor {<br /><br /> println(">>keyProcessorActor starting")<br /><br /> var key : Option[Char] = null<br /><br /> loop {<br /><br /> react {<br /> case 'q' => exit() // 'q' signifies quit app!<br /> case x : Char => println("keyProcessorActor received '" + x + "'")<br /><br /> sleep ! 1000 // ask the sleep actor to sleep, we will get a Wakeup call when done<br /><br /> // now wait for our wakeup<br /> var r = false<br /><br /> do {<br /> receive {<br /> case Wakeup => r = true<br /> }<br /> } while (!r)<br /> }<br /> }<br /><br /> println("<<keyProcessorActor ending")<br /> }<br /><br /> val kbReaderActor = actor {<br /><br /> println(">>kbReaderActor starting")<br /><br /> var key : Char = ' '<br /><br /> do {<br /><br /> println("kbReaderActor waiting for input")<br /> val i = System.in.read()<br /> <br /> key = i.asInstanceOf[Char]<br /><br /> println("Received input " + key)<br /><br /> // message actor1 with the key read from the console<br /> keyProcessorActor ! key<br /> <br /> } while (key != 'q')<br /><br /> println("<<kbReaderActor ending")<br /> }<br /> <br /> println("<<Application Ending")<br /> }<br />}<br /></pre><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-66651303794258857512009-06-06T08:50:00.000-07:002009-06-06T09:31:10.350-07:00Quantum Entanglement, entanglement with 2 electron singlet(and now for something completely different... Quantum mechanics and quantum entanglement)<br /><span style="font-weight: bold;"><br />Quantum Entanglement:</span> Entanglement with 2 element quantum singlet.<br /><br />Having recently emailed <span style="font-weight: bold;">Leonard Susskind</span> (Stanford CA) with a question regarding entanglement of a 3rd element with a 2 element system in the quantum singlet state (an entangled pair).<br /><br />Leonard Susskind is the Felix Bloch professor of theoretical physics at <a href="http://en.wikipedia.org/wiki/Stanford_University" title="Stanford University">Stanford University</a> in the field of <a href="http://en.wikipedia.org/wiki/String_theory" title="String theory">string theory</a> and <a href="http://en.wikipedia.org/wiki/Quantum_field_theory" title="Quantum field theory">quantum field theory</a> <a href="http://en.wikipedia.org/wiki/Leonard_Susskind">http://en.wikipedia.org/wiki/Leonard_Susskind</a><br /><br />Susskind is widely regarded as one of the fathers of String Theory.<br /><br />So naturally, I was somewhat surprised when I actually got a detailed response, and the answer is very interesting and informative too! Like most things in Quantum mechanics, the result is not something that could be guest or anticipated, it's not something that could be expected using classical intuition or experience.<br /><br /><br /><span style="font-weight: bold;">Here is the reply:</span><br /><br />--<br /><div id="doc-contents"><p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >Let’s begin with the initial state consisting of two electrons in a singlet state |ud-du> .( I should include a factor of one-over-square-root-of-2 to normalize the state but it’s too hard to type in Word so I will leave it to you.) Now add another electron in the up state— |u). Also, in order to keep track of photons, lets indicate that there are no photons present with the notation |0}. The initial state is,</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |ud-du> |u) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |0} </span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >Now let’s rearrange the symbols so as to group electrons 2 and 3 together. This is just a notational device. The initial state is</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:6;" > [</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du) - |d>|uu) </span><span style=";font-family:Times New Roman;font-size:6;" >] </span><span style=";font-family:Times New Roman;font-size:100%;" >|0}</span><br /><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >Now use the trivial identity</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >|du) = ½ |du-ud) + ½ |du+ud)</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >to rewrite it </span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >=½ </span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du-ud) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |0} + ½ </span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du+ud) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |0}</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" > -</span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |d>|uu) </span><span style=";font-family:Times New Roman;font-size:6;" >] </span><span style=";font-family:Times New Roman;font-size:100%;" >|0}</span><br /><br /><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >Now think of electron 2 and 3 as close one another, while electron 1 is off in the distance. In the first term 2-3 are in a singlet state. Nothing happens to it. In the other two terms the 2-3 system is orthogonal to the singlet. The 2-3 system will interact to emit a photon, and decay to the singlet in those cases, although the photons will be in different states in the two terms. Denoting the presence of the photon by |γ} and |γ’}, the final state will be</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >=½ </span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du-ud) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |0} + ½ </span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du-ud) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |γ}</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" > -</span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |d>|du-ud)</span><span style=";font-family:Times New Roman;font-size:6;" >] </span><span style=";font-family:Times New Roman;font-size:100%;" >|γ’} (note, there is missing sqrt2)</span><br /></p> <p style="color: rgb(51, 0, 153);"><span style=";font-family:Times New Roman;font-size:100%;" >So what do we have in the end? A superposition of states in which the 2-3 system is in the singlet and</span><br /></p> <ol style="color: rgb(51, 0, 153);" type="a"><li><span style=";font-family:Times New Roman;font-size:100%;" >electron 1 is up with no photon</span></li></ol><span style="color: rgb(51, 0, 153);"> </span><br /><ol style="color: rgb(51, 0, 153);" start="2" type="a"><li><span style=";font-family:Times New Roman;font-size:100%;" > electron 1 is up with a photon in state |γ}</span></li></ol><span style="color: rgb(51, 0, 153);"> </span><br /><ol style="color: rgb(51, 0, 153);" start="3" type="a"><li><span style=";font-family:Times New Roman;font-size:100%;" >electron 1 is down with a photon in state </span> <span style=";font-family:Times New Roman;font-size:100%;" >|γ’}. </span></li></ol><span style="color: rgb(51, 0, 153);"> </span><br /><span style="color: rgb(51, 0, 153);font-family:Times New Roman;font-size:100%;" >If there is no photon or a photon in state |γ} then we know that electron 1 is up. If there is a photon in state |γ’} then e-1 must be down.</span><br /><br />--<br /><br />Having such a brilliantly and concise response was fantastic!<br /><br />I've gone on to calculate the trivial equations to determine the probability in each state, as follows:<br /><br />Given the probabilities of the 3 possibilities must add up to 1, taking the coefficients as lambda, the probability is given by lambda.lambda* which for real numbers is just lambda^2, so:<br /><br /><span style=";font-family:Times New Roman;font-size:100%;" >=½ </span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du-ud) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |0} + ½ </span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |u> |du-ud) </span><span style=";font-family:Times New Roman;font-size:6;" >]</span><span style=";font-family:Times New Roman;font-size:100%;" > |γ}</span><br /><span style=";font-family:Times New Roman;font-size:100%;" > -</span><span style=";font-family:Times New Roman;font-size:6;" >[</span><span style=";font-family:Times New Roman;font-size:100%;" > |d>|du-ud)</span><span style=";font-family:Times New Roman;font-size:6;" >] </span><span style=";font-family:Times New Roman;font-size:100%;" >|γ’} (note, there is missing sqrt2)</span><br /><span style=";font-family:Times New Roman;font-size:100%;" ><br /><span style="font-weight: bold;">a.</span> electron 1 is up with no photon</span><br /><pre><br />| 1 | 2<br />| ------------| = 1/4 = p1 = <span style="font-weight: bold;">0.25</span><br />| 2 sqrt(2) |<br /></pre><br /> <span style="font-size:100%;"><span style="font-weight: bold;">b.</span> elect</span>ron 1 is up with a photon in state |γ}<br /><br /> p2 = <span style="font-weight: bold;">0.25</span><br /><br /><br /> <span style="font-weight: bold;">c.</span> electron 1 is down with a photon in state |γ’}.<br /><pre><br />| 1 | 2<br />| ------------| = 1/2 = p3 = <span style="font-weight: bold;">0.5</span><br />| sqrt(2) |<br /><br /></pre><br /></div><span style="font-weight: bold;">Google document:</span><br /><br /><a id="publishedDocumentUrl" class="tabcontent" target="_blank" href="http://docs.google.com/View?id=df4zskcg_25d8xtc9hp">http://docs.google.com/View?id=df4zskcg_25d8xtc9hp</a><br /><br /><br />The Stanford course "Modern Theoretical Physics - Fall 2006" by Leonard Susskind is available on iTunes-U (highly recommended!).<br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-26423589468926203312009-06-06T08:02:00.000-07:002009-06-06T08:12:35.583-07:00Basic Crib sheet for Mercurial hgMercurial (hg) is a distributed version control system, with many similarities to Subversion (svn). Being distributed, means people can work offline and still keep their version history local, merging changes with each other by exporting and importing the repository changes periodically.<br /><br />Generally speaking mercurial is very simple and easy to use, but here are a few commands for quick reference:<br /><br /><br /><span style="font-weight: bold;">Basic crib for Mecurial HG</span><br /><br />Clone a repository from a web URL:<br /><br /><span style="font-family: courier new;">hg clone http://www.selenic.com/repo/hello my-hello</span><br /><br />Clone from another local repository:<br /><br /><span style="font-family: courier new;">hg clone existing-repos clone-repos</span><br /><br />Make a new repository:<br /><br /><span style="font-family: courier new;">hg init</span><br /><br />Add files:<br /><br /><span style="font-family: courier new;">hg add</span><br /><br />Committing changes:<br /><br /><span style="font-family: courier new;">hg commit (hg ci)</span><br /><br />Pull changes from one repository to another:<br /><br /><span style="font-family: courier new;">hg pull <repository></span><br /><br />Note: this doesn't update the working directory, to do this update the working directory:<br /><br /><span style="font-family: courier new;">hg update (hg up)</span><br /><br />Exporting and import:<br /><br /><span style="font-family: courier new;">hg export -o filename tip</span><br /><br /><span style="font-family: courier new;">hg import -o filename </span><br /><br />Other common commands:<br /><br /><span style="font-family: courier new;">hg log</span><br /><span style="font-family: courier new;">hg status (hg st)</span><br /><span style="font-family: courier new;">hg diff</span><br /><span style="font-family: courier new;">hg revert</span><br /><span style="font-family: courier new;">hg (-q) tip</span><br /><br /><br /><span style="font-weight: bold;">HG Editor</span>, the editor for HG comments is determined in the following order:<br /><br />HGEDITOR environment variable<br /><br />editor configuration option in [ui] section (in hgrc or passed with --config ui.editor command-line option).<br /><br />VISUAL environment variable<br /><br />EDITOR environment variable<br /><br />vi, if none of the above is set<br /><br /><br /><span style="font-weight: bold;">References:</span><br /><br />Mercurial home:<br /><a href="http://www.selenic.com/mercurial/wiki/Mercurial"><br />http://www.selenic.com/mercurial/wiki/Mercurial</a><br /><br />Mecurial tutorial:<br /><br /><a href="http://www.selenic.com/mercurial/wiki/Tutorial">http://www.selenic.com/mercurial/wiki/Tutorial</a><br /><br />Quick reference and cheat sheets:<br /><br /><a href="http://www.selenic.com/mercurial/wiki/QuickReferenceCardsAndCheatSheets">http://www.selenic.com/mercurial/wiki/QuickReferenceCardsAndCheatSheets</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-85616121715280155722009-06-04T11:51:00.000-07:002009-06-04T14:11:01.010-07:00GlassFish v2.1 b60e crib sheet / installation notes<p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Recently, having been working on a project that's migrated from JBoss 4.2.2 to GlassFish v2.1, I needed to hand over a crib sheet / quick guide to people supporting the live system, so as it might be useful in general. Only really covering the basics, but here it is anyway:</span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"></span></span><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">GlassFish AS Basic Crib / notes:</span></span></b></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Prerequisites:</span></span></p> <ul style="margin-top: 0cm;" type="disc"><li><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Java JDK 6.x latest</span></span><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></li></ul> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">GlassFish AS version V2.1 b60e Final Release</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Download jar here <a href="http://java.net/download/javaee5/v2.1_branch/promoted/Linux/glassfish-installer-v2.1-b60e-linux.jar" target="_blank">http://java.net/download/<wbr>javaee5/v2.1_branch/promoted/<wbr>Linux/glassfish-installer-v2.<wbr>1-b60e-linux.jar</a></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">For RHEL derived CentOS, recommended installation would be something like <span style="font-family: courier new;">/usr/local/projectname/</span><wbr style="font-family: courier new;"><span style="font-family: courier new;">glassfish</span></span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Installation:</span></span></b></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"></span><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">java -Xmx256m -jar glassfish-installer-v2.1-b60e-<wbr>linux.jar</span></span></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">cd glassfish</span></span></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">chmod -R +x lib/ant/bin</span></span></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">lib/ant/bin/ant -f setup.xml</span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"> </span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Follow the installer instructions, accepting EULA and any defaults presented...<br /></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">This will unpack and install the server, creating a default domain called "domain1"</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">A domain is an administrative "unit" - possibly related to, but not the same as an actual domain.<br /></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">All domains live in: <span style="font-family: courier new;">{glassfish_home}/domains/</span></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">We need just one for now, so all our stuff will be in:<br /></span></span></p> <p style="font-family: courier new;"><span style="font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">{glassfish_home}/domains/<wbr>domain1/</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">the installation process will create a default empty domain, domain1 with a default config file, the main configuration file is called <b><span style="font-weight: bold;">domain.xml</span></b></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">e.g. </span></span><span style="font-family:Courier New;"><span style="font-family: "Courier New";" lang="EN-GB">{glassfish_home}/domains/<wbr>domain1/config.xml</span></span><span lang="EN-GB"></span><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">This file may contain some host /installation specific information, as well as stuff specific to our application.</span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p><p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Starting and stopping GlassFish AS:</span></span></b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">{glassfish_home}/bin/asadmin start-domain domain1</span></span></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">{glassfish_home}/bin/asadmin stop-domain domain1</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"> </span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">If all is good you will see confirmation on the command prompt when started, such as:</span></span></p> <p><i><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-style: italic;" lang="EN-GB">Domain domain1 started</span></span></i></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Managing GlassFish AS:</span></span></b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">By default, the web based management console is available on port :4848</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">The default admin account is username = admin, password = adminadmin</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">URL is: http://{hostname}:4848</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Web-app deployment options:</span></span></b></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">There are a few options, the main two are:</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Manually, using autodeploy directory</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Simply copy .war file to: </span></span><span style="font-family:Courier New;"><span style="font-family: "Courier New";" lang="EN-GB">{glassfish_home}/domains/<wbr>domain1/autodeploy</span></span><span lang="EN-GB"></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Deploying via the admin console:</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">On main menu on left, click on and expand the Web Applications menu entry</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Click on the Deploy button, typically when deploying from a local file, use the "Packaged file to be uploaded to the server" browse button to locate the local war file. Browse for the war file, select it and click Ok</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">When completed, the web app will appear in the application list (if all is well)</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">The other settings can be left as defaults. Optionally we can chose to pre-compile JSPs here etc.</span></span></p> <p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB"><br /></span></span></b></p><p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Server Logs:</span></span></b></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">The main server logs appear in the domain under logs, i.e.<br /></span></span></p> <p><span style="font-family:Courier New;font-size:100%;"><span style="font-size: 12pt; font-family: "Courier New";" lang="EN-GB">{glassfish_home}/domains/<wbr>domain1/logs/server.log</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Logs can also be viewed (and configured, including log rotation) via the admin console, under the Application Server menu entry</span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Monitoring and management:</span></span></b></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">JConsole:</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">GlassFish is a JMX compliant app server (listening by default to port 8686)</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Using jconsole, remote connect to: </span></span><span style="font-family:Courier New;"><span style="font-family: "Courier New";" lang="EN-GB">http://{hostname}:8686</span></span><span lang="EN-GB"></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Using the same default account: </span></span><span style="font-family:Courier New;"><span style="font-family: "Courier New";" lang="EN-GB">admin/adminadmin</span></span><span lang="EN-GB"></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"> </span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"></span></span><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">Admin console:</span></span></b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">Under the Application Server in the main menu - there are entries for server Monitoring.</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">This includes a built in chart and call flow logging - which is potentially very useful for diagnostics and monitoring…<br /></span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p> <p><b><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt; font-weight: bold;" lang="EN-GB">HTTPS / SSL:</span></span></b></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">GlassFish AS will do HTTPS out of the box (using a default Sun Microsystems certificate).</span></span></p> <p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">HTTPS is served by default on port <b><span style="font-weight: bold;">:8181</span></b></span></span></p><p><br /><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><b><span style="font-weight: bold;"></span></b></span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><b><span style="font-weight: bold;">Hopefully in the near future I'll but together something to cover clustering and load balancing too.<br /></span></b></span></span></p><p><span style="font-size:100%;"><br /></span><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"></span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB"><br /></span></span></p><p><span style="font-family:Times New Roman;font-size:100%;"><span style="font-size: 12pt;" lang="EN-GB">.<b><span style="font-weight: bold;"><br /></span></b></span></span></p>LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-24572069465182521342009-06-03T11:20:00.000-07:002009-06-03T11:30:37.138-07:00Super quick guide for creating self-signed certificatesSomething I've done many times, but every time it's typically been so long in between that I've usually forgotten the specific details, so here is a super quick crib:<br /><br />Create the private keys:<br /><br /><pre><br />openssl genrsa -des3 -out server1.key 1024<br /></pre><br /><br />Create a Certificate Signing Request (CSR):<br /><br /><pre><br />openssl req -new -key server1.key -out server1.csr<br /></pre><br /><br />Enter details, example below:<br /><br /><pre><br />Country Name (2 letter code) [AU]:GB<br />State or Province Name (full name) [Some-State]:Kent<br />Locality Name (eg, city) []:Royal Tunbridge Wells<br />Organization Name (eg, company) [Internet Widgits Pty Ltd]:Acme Co<br />Organizational Unit Name (eg, section) []:Financial Systems<br />Common Name (eg, YOUR name) []:www.myexactdomainname.com<br />Email Address []:louis.botterill@netbuilder.com<br /><br />Please enter the following 'extra' attributes<br />to be sent with your certificate request<br />A challenge password []:<br />An optional company name []:<br /></pre><br /><br />Copy the passphrase protected key:<br /><br /><pre><br />cp server1.key server1.key.org<br /></pre><br /><br />Export the actual key without pass-phrase protection:<br /><br /><pre><br />openssl rsa -in server1.key.org -out server1.key<br /></pre><br /><br />Sign the CSR using the key to create a Certificate (.crt):<br /><br /><pre><br />openssl x509 -req -days 365 -in server1.csr -signkey server1.key -out server1.crt<br /></pre><br /><br />Easy huh! :)<br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-61796939767908221972009-05-21T13:36:00.000-07:002009-05-21T14:59:07.781-07:00How to add GZIP compression to a .NET WCF REST POX client<span style="font-weight: bold;">Bandwidth is important!</span> Even these days where everyone has broadband, now we want the same performance on the move, over wireless and 3G networks. Even when clients individually have enough bandwidth, put 100 or 1000 users together in a corporate environment and it's the IT department that may start have the headache instead. Then there's the server side, ultimately all this traffic comes together down a finite number of "pipes" to our servers, so really we still have to consider bandwidth usage at all levels.<br /><br /><span style="font-weight: bold;">We needed to add GZip compression support to a .NET 3.5sp1 client application using WCF for REST POX web services.</span> The responses were sent compressed using GZIP, so the client needed to be able to decompress these, before passing up the stack to the Data Serialisers and application code layers.<br /><br /><span style="font-weight: bold;">The server in this instance is a Java EE web application returning XML, GZipped using a filter servlet.</span> Implementing the server side filter is fairly trivial, however it's companion in .NET on the client side is not.<br /><br />Since this gave me a little bit of a challenge recently (very little documentation around or good examples) I thought I'd put up a quick blog about it. It's not that there's a lot of code involved, it's understanding the WCF with sufficient clarity to be able to extend it, and debug it when it's not quite right.<br /><br />One of the issues that crops up straight away is that most examples of extending the WCF for compression are based around the WS.* web service support, the original incarnation of WCF.<br /><br />However, later versions of the WCF added support for REST/POX web services, and this is where I wanted to add the GZIP compression support. <span style="font-weight: bold;">You can not mix WS.* and Rest (aka Web in WCF) web services in the WCF, without creating a runtime error as the WCF channel is instantiated.</span><br /><br />So, enough of the preamble already, lets cut to the chase, what's needed?<br /><br />Well, assuming you have a WebHttpBinding to start with...<br /><br /><span style="font-family:courier new;">WebHttpBinding webHttpBinding = new WebHttpBinding();</span><br /><br /><br />Then, in order to add the GZIP compression support, we need to pull apart the binding, into its constituent elements and then reassemble it, adding in the new binding element.<br /><br />I enlisted the help of a content mapper to force the content to XML:<br /><br /><pre><br />public class XMLMapper : WebContentTypeMapper<br />{<br /> public override WebContentFormat GetMessageFormatForContentType(string contentType)<br /> {<br /> return WebContentFormat.Xml; // always<br /> }<br />}<br /></pre><br /><br /><br /><br />First, get the binding elements out of the WebHttpBinding, using the CreateBindingElements() function.<br /><br /><pre><br />BindingElementCollection bec = webHttpBinding.CreateBindingElements();<br /><br />WebMessageEncodingBindingElement wmbe = bec.Remove<webmessageencodingbindingelement>();<br />HttpTransportBindingElement htbe = bec.Remove<httptransportbindingelement>();<br /><br />wmbe.ContentTypeMapper = new XMLMapper();<br /><br />GZipMessageEncodingBindingElement compBindingElement = new GZipMessageEncodingBindingElement(wmbe);<br /><br />bec.Add(compBindingElement);<br />bec.Add(htbe);<br /><br />CustomBinding cb = new CustomBinding(bec);<br /><br />binding = cb;<br /><br />HttpRequestMessageProperty httpRequestMessageProperty = new HttpRequestMessageProperty();<br /><br />httpRequestMessageProperty.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip");<br />httpRequestMessageProperty.Headers.Add(HttpRequestHeader.ContentEncoding, "gzip");<br /></httptransportbindingelement></webmessageencodingbindingelement><br /></pre><br /><br /><br />Ok, so now binding is a rebuilt binding, based on WebHttpBinding where a GZIP encoder has been used to wrap the <span style="font-family:courier new;">WebMessageEncodingBindingElement</span> from the original binding's binding elements.<br /><br />Note that the <span style="font-family:courier new;">HttpTransportBindingElement</span> must be the last binding element in the binding element collection (protocol stack) or a runtime error will be thrown when trying to instantiate the channel.<br /><br />Now we can create the channel in the normal way:<br /><br /><pre><br />// create a channel factory<br />ChannelFactory<iservice> cf = new ChannelFactory<iservice>(binding, hostPath);<br /> <br />// create webhttpbehavior for rest / pox get/invoke behaviour support<br />WebHttpBehavior webHttpBehavior = new WebHttpBehavior();<br />webHttpBehavior.DefaultOutgoingRequestFormat = WebMessageFormat.Xml;<br />webHttpBehavior.DefaultOutgoingResponseFormat = WebMessageFormat.Xml;<br /> <br />// add webhttpbehahvior to channelfactory endpoint<br />cf.Endpoint.Behaviors.Add(webHttpBehavior);<br /><br />if (ENABLE_COMPRESSION)<br />{<br /> // add our custom behavior...<br /> cf.Endpoint.Behaviors.Add(new HttpEndpointBehavior());<br />}<br /><br />// create our IService channel<br />channel = cf.CreateChannel();<br /></iservice></iservice></pre><br /><br /><br />So far so good, but what about this <span style="font-family:courier new;">GZipMessageEncodingBindingElement</span>?<br /><br />Well, this can be found in the Microsoft WCF samples:<br /><br /><a href="http://msdn.microsoft.com/en-us/library/ms751458.aspx">http://msdn.microsoft.com/en-us/library/ms751458.aspx</a><br /><br /><br />Detailed steps of integrating the MS WCF GZip example into your code:<br /><br /><a href="http://www.vistax64.com/indigo/113763-wcf-client-j2ee-server-using-gzip.html">http://www.vistax64.com/indigo/113763-wcf-client-j2ee-server-using-gzip.html</a><br /><br />Note: I had to make some minor modifications to make my client work correctly, details can be provided if anyone leaves a comment expressing an interest.<br /><br /><br /><br /><span style="font-weight: bold;">Further Resources:</span><br /><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><br />Various threads discussing similar problems:<br /></span></span> <p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><a href="http://social.msdn.microsoft.com/forums/en-US/wcf/thread/5c67b0da-9e50-4ee1-b7ac-a4733c580980/" target="_blank">http://social.msdn.microsoft.<wbr>com/forums/en-US/<span class="il">wcf</span>/thread/<wbr>5c67b0da-9e50-4ee1-b7ac-<wbr>a4733c580980/</a></span></span></p> <p><span style="font-size:100%;"><br /></span></p><p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><a href="http://social.msdn.microsoft.com/forums/en-US/wcf/thread/ddfe06b1-f07c-4da2-a1f1-d06126e4f96e/" target="_blank">http://social.msdn.microsoft.<wbr>com/forums/en-US/<span class="il">wcf</span>/thread/<wbr>ddfe06b1-f07c-4da2-a1f1-<wbr>d06126e4f96e/</a></span></span></p> <p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><br /></span></span></p> <p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><a href="http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24644" target="_blank">http://aspnet.codeplex.com/<wbr>Release/ProjectReleases.aspx?<wbr>ReleaseId=24644</a></span></span></p><span style="font-size:100%;"><br /></span><p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;">Neomax - provide software products to extend the WCF framework, including support for compression:<br /></span></span></p> <p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><a href="http://www.noemax.com/products/wcfx/features.html#gzip_compression" target="_blank">http://www.noemax.com/<wbr>products/wcfx/features.html#<wbr>gzip_compression</a></span></span></p><p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><a href="http://www.noemax.com/products/wcfx/features.html#gzip_compression" target="_blank"><br /></a></span></span></p> <h2 style="font-weight: normal;font-family:arial;"><span style="font-size:100%;">Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1: BETA</span></h2> <p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"><a href="http://www.microsoft.com/downloads/thankyou.aspx?familyId=a91dc12a-fc94-4027-b67e-46bab7c5226c&displayLang=en" target="_blank">http://www.microsoft.com/<wbr>downloads/thankyou.aspx?<wbr>familyId=a91dc12a-fc94-4027-<wbr>b67e-46bab7c5226c&displayLang=<wbr>en</a></span></span></p> <p><span style=";font-family:Arial;font-size:100%;" ><span lang="EN-GB" style="font-family:Arial;"></span></span><br /></p><p>.<br /></p>LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com4tag:blogger.com,1999:blog-89287579799971239.post-62533464189580865892009-05-16T15:03:00.000-07:002009-05-31T14:00:45.228-07:00Quick notes on OpenSolaris 111a & GlassFish clusteringSome quick notes on upgrading 111 to 111a and preparing for GlassFish v2.1 clustering and load balancing tests:<br /><br />(Note: This is really a scratch-pad of notes and resources for my own benefit, rather than a structured Blog for others to follow, however some of the resources might be useful for someone, somewhere)<br /><br /><span style="font-weight: bold;">OpenSolaris upgrade problems:</span><br /><br />Graphical login failed to start<br /><br />Simply restarting gdm fixed this problem!<br /><br /><span style="font-family:courier new;">svcadm disable gdm</span><br /><span style="font-family:courier new;">svcadm enable gdm</span><br /><br /><br /><span style="font-weight: bold;">Installing GlassFish v2.1 - problems:</span><br /><br />Running java -Xmx256m -jar glassfish_xxx.jar reported "Not Enough Space Available"<br /><br />zfs list showed 8gig space available<br /><br />check for large files in swap directories:<br /><br /><span style="font-family:courier new;">pfexec du -k /tmp|sort -n</span><br /><span style="font-family:courier new;">pfexec du -k /etc/svc/volatile|sort -n</span><br /><br />Increasing swap space, adding a second swap file:<br /><br /><span style="font-family:courier new;">zfs create -V2G rpool/swap2 ; swap -a /dev/zvol/dsk/rpool/swap2</span><br /><br /><br /><span style="font-weight: bold;">GlassFish clustering:</span><br /><br />Steps for setting up GlassFish clustering:<br /><br />Setup default clustering profile;<br /><br /><span style="font-family:courier new;">lib/ant/bin/ant -f setup-cluster.xml</span> <span style="font-family:courier new;"><br /><br /></span>Start the DAS;<br /><span style="font-family:courier new;"><br />bin/asadmin start-domain --user admin</span> <span style="font-family:courier new;"></span> <span style="font-family:courier new;"><br /><br /></span>Create the node agent;<br /><br /><span style="font-family:courier new;">bin/asadmin create-node-agent</span><br /><br />Start the node agent;<br /><br /><span style="font-family:courier new;">bin/asadmin start-node-agent</span><br /><br />Create cluster and instances (for node agent) in GlassFish admin console.<br /><br />Download Load Balancer plug-in according to platform<br /><br /><a href="http://download.java.net/javaee5/external/">http://download.java.net/javaee5/external/</a><br /><br /><br /><span style="font-weight: bold;">Guide to setting up GlassFish clustering:</span><br /><a href="http://blogs.sun.com/dadelhardt/entry/clustering_web_applications_with_glassfish1"><br />http://blogs.sun.com/dadelhardt/entry/clustering_web_applications_with_glassfish1</a><br /><br /><br />Guide to setting up GlassFish with Load Balancer plugin:<br /><br /><a href="https://glassfish.dev.java.net/javaee5/build/GlassFish_LB_Cluster.html">https://glassfish.dev.java.net/javaee5/build/GlassFish_LB_Cluster.html</a><br /><br /><span style="font-weight: bold;">Further resources:</span><br /><br />Clustering with Apache HTTPd:<br /><br /><a href="http://blogs.sun.com/jluehe/entry/supporting_apache_loadbalancer_with_glassfish">http://blogs.sun.com/jluehe/entry/supporting_apache_loadbalancer_with_glassfish</a><br /><br /><br />Interesting thread about clustering problems:<br /><br /><a href="http://www.nabble.com/Cluster-session-replication-not-working-td20691318.html">http://www.nabble.com/Cluster-session-replication-not-working-td20691318.html</a><br /><br /><br />GlassFish V2 Clustering presentation:<br /><br /><a href="http://blogs.sun.com/stripathi/resource/Preso/GlassFishv2Clustering.pdf">http://blogs.sun.com/stripathi/resource/Preso/GlassFishv2Clustering.pdf</a><br /><br />Sun Clustering with GlassFish v2:<br /><br /><a href="http://developers.sun.com/appserver/reference/techart/glassfishcluster/">http://developers.sun.com/appserver/reference/techart/glassfishcluster/</a><br /><br /><br />Setting up GlassFish SSL support:<br /><br /><a href="http://java.sun.com/mailers/techtips/enterprise/2007/TechTips2_Nov07.html">http://java.sun.com/mailers/techtips/enterprise/2007/TechTips2_Nov07.html</a><br /><br /><br />GlassFish JMX / JConsole:<br /><br /><a href="http://docs.sun.com/app/docs/doc/820-4335/ablwi?a=view">http://docs.sun.com/app/docs/doc/820-4335/ablwi?a=view</a><br /><br /><br /><span style="font-weight: bold;">Sun Java web server (for load balancing):</span><br /><br /><a href="https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=SJWS6.1SP5-OTH-G-F@CDS-CDS_SMI">https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_SMI-Site/en_US/-/USD/ViewProductDetail-Start?ProductRef=SJWS6.1SP5-OTH-G-F@CDS-CDS_SMI</a>LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-59758078492530795702009-04-08T11:58:00.000-07:002009-04-08T15:14:47.089-07:00Cloud computing - cloudforce and beyond...Having recently attended Cloudforce UK - London (07th-04-2009) I though I'd blog a little with some resources and links.<br /><br />I don't really want to re-invent the wheel and attempt to explain what cloud computing is exactly, hopefully some of the resources and links should cover that. For an overview, the Wikipedia entry is a good start <a href="http://en.wikipedia.org/wiki/Cloud_computing">http://en.wikipedia.org/wiki/Cloud_computing</a><br /><br />A couple of terms that crop up in this domain are:<br /><ul><li>SaaS - Software as a Service</li><li>PaaS - Platform as a Service</li><li>IaaS - Infrastructure as a Service<br /></li></ul><br />Cloudforce itself is a worldwide tour of salesforce.com - evangelising and spreading the word about their cloud products and frameworks, customer success stories and break out sessions covering aspects from development to opportunities.<br /><br />Details on the event <a href="http://www.chinwag.com/events/2009/04/cloudforce-london-2009">http://www.chinwag.com/events/2009/04/cloudforce-london-2009</a><br /><br /><br /><span style="font-weight: bold;">Salesforce cloud platform:</span><br /><br /><a href="http://www.salesforce.com/platform/">http://www.salesforce.com/platform/<br /></a><br /><br />Main features at a glance:<br /><ul><li>Product portfolio including CRM</li><li>Application store - the AppExchange<br /></li><li>Multiple server, massively scalable environment</li><li>Multi-tenant database optimised for cloud usage</li><li>Disaster recovery</li><li>Database, web service, business logic and presentation layers</li><li>Fast app creation, instant deployment</li><li>Live update of applications, can copy to sandbox to develop new versions</li><li>No built in source code control / visioning</li><li>Eclipse force plug ins available for development integration</li><li>Presentation framework and components (Visual Force)</li><li>Strongly types OO language - Apex (an on-demand language)</li><li>Web service creation API and integration support<br /></li><li>Integration with Mobile devices - iPhone, Blackberry and Windows mobile based devices</li><li>Integration with Twitter, Facebook, Google API's supported<br /></li></ul><br /><span style="font-weight: bold;">Site gallery / reference sites:</span><br /><br /><a href="http://developer.force.com/sitesgallery">http://developer.force.com/sitesgallery<br /></a><br /><br /><span style="font-weight: bold;">Force.com Applications:</span><br /><br />The platform has an App Exchange, a place where cloud based applications can be shared and exchanged <a href="http://www.salesforce.com/platform/appexchange/">http://www.salesforce.com/platform/appexchange/</a><br /><br />The Salesforce platform offers a number of off the shelf, customisable applications products, such as Salesforce CRM <a href="http://www.salesforce.com/products/">http://www.salesforce.com/products/</a><br /><br /><br /><span style="font-weight: bold;">App Development:</span><br /><br />Salesforce developer home is here <a href="http://developer.force.com/">http://developer.force.com/</a><br /><br />The platform framework offers some technologies such as Visual Force for GUI components and component creation and Apex for code/page creation - <a href="http://wiki.developerforce.com/index.php/Apex">http://wiki.developerforce.com/index.php/Apex</a><br /><br />Salesforce blerb about Apex "Force.com Apex Code is a strongly-typed programming language that executes on the Force.com platform. Apex is used to add business logic to applications, to write database triggers, and to program controllers in the user interface layer. It has a tight integration with the database and query language, good web services support, and includes features such as futures and governors for execution in a multi-tenant environment."<br /><br /><br /><span style="font-weight: bold;">Cloudforce take-aways:</span><br /><br />As well as the above, the overall event gave an impression of some key takeaway points.<br /><br /><ul><li>The service cloud, service applications now integrating and utilising knowledge from social networking sources such as Twitter, Facebook etc as well as traditional sources such as Phone. </li><li>Easy of application creation</li><li>Speed of development</li><li>Enable business to meet customer demands in terms of cost or time to market that might otherwise be impossible<br /></li></ul><br /><span style="font-weight: bold;">Some other providers:</span><br /><br />Many over companies offer computing in the cloud, such as:<br /><br /><ul><li>Microsoft - Windows Azure <a href="http://en.wikipedia.org/wiki/Azure_Services_Platform">http://en.wikipedia.org/wiki/Azure_Services_Platform</a><br /></li><li>Google - App engine <a href="http://code.google.com/appengine/">http://code.google.com/appengine/</a> - recently with support for Java! read more here <a href="http://blogoscoped.com/archive/2009-04-08-n87.html">http://blogoscoped.com/archive/2009-04-08-n87.html</a></li><li>3tera - <a href="http://www.3tera.com/">http://www.3tera.com/</a></li><li>SAP AG - SAP business as a service <a href="http://en.wikipedia.org/wiki/SAP_Business_ByDesign">http://en.wikipedia.org/wiki/SAP_Business_ByDesign</a></li><li>Amazon - EC2 (Elastic Compute Cloud) - <a href="http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud">http://en.wikipedia.org/wiki/Amazon_Elastic_Compute_Cloud</a><br /></li></ul><br /><br />Well, having just signed up for the Google App engine, expect more blogs in the future as I play around and experiment up in the clouds...<br /><br /><br /><span style="font-weight: bold;">Further Resources:</span><br /><br />Google AppEngine blogspot - <a href="http://googleappengine.blogspot.com/">http://googleappengine.blogspot.com/</a><br /><br />Sun Cloud Computing Primer (Need a Sun account) - <a href="http://www.sun.com/offers/details/cloud_computing_primer.html">http://www.sun.com/offers/details/cloud_computing_primer.html</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-53014686204631327762009-04-02T14:18:00.000-07:002009-04-10T06:45:15.547-07:00.NET and C# - an introductionNot so much an actual blog today, rather a link to a presentation I recently gave as an introduction to the .NET framework and C# - to a mixed audience of C, C++, Java and web developers.<br /><br />It's mainly a high level overview of the .NET framework and then an introduction to the C# language, from a programmers perspective, for programmers familiar with other languages like Java and C++, to help get familiar with the basics.<br /><a href="http://www.chillipower.com/Primers/IntroductionToDotNetandCsharpPresentation.odp"><br /></a><br />Available in OpenOffice format ODP:<br /><a href="http://www.chillipower.com/Primers/IntroductionToDotNetandCsharpPresentation.odp">http://www.chillipower.com/Primers/IntroductionToDotNetandCsharpPresentation.odp</a><br /><br />Or MS PowerPoint presentation format PPT:<br /><a href="http://www.chillipower.com/Primers/IntroductionToDotNetandCsharpPresentation.ppt">http://www.chillipower.com/Primers/IntroductionToDotNetandCsharpPresentation.ppt</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-69481307546522447362009-03-30T04:27:00.000-07:002009-04-01T10:58:47.352-07:00Some notes from Sun GlassFish portfolio tech talk, LondonSun GlassFish and GlassFish portfolio - Sun talk London, Regis House 25-03-2009<br /><br />Some notes that I managed to take whilst at the talk.<br /><br /><a href="http://www.glassfish.org/">www.glassfish.org</a><br /><br />Claimed to be the fastest Java EE AS<br /><br />V2.0 -> reference implementation for Java EE 5<br />V3.x -> reference implementation for Java EE 6<br /><br />Java EE standard 10 years old<br /><br />Metro -> Interop between MS and Java WS.* standards<br /><br />GlassFish is Open Source under CDDL and GPL 2 license<br /><br /><a href="http://java.sun.com/javaee">java.sun.com/javaee</a><br /><br />Transparent development<br /><br />Organic growth into middleware areas<br /><br />First appearance 2005<br />V2 in 2007<br />Current v2.1 in Feb 2009<br /><br /><a href="http://www.beta.glassfish.java.net:81/maps">www.beta.glassfish.java.net:81/maps</a><br /><br />6-700 downloads per month, 8 million in the last year / ~28k per day<br /><br />GlassFish portfolio is a set of related technologies including the AS<br /><ul><li> Enterprise server (including support for SNMP)</li><li> Web space server (joined with Life Ray - social networking & portal technologies)</li><li> Web sack (a complete (L)(S)(?)AMP stack)</li><li> GlassFish ESB (SOA platform) for integration, connectors, adaptors</li></ul><br />Java EE + Ruby on Rails, PHP and other frameworks<br /><br />(note - what is SFA?)<br /><br /><span style="font-weight: bold;">Enterprise version adds:</span><br /><ul><li>Performance advisor, performance monitor, SNMP, self management and alert manager</li><li>Update center<br /></li></ul><br /><span style="font-weight: bold;">Example / reference sites:</span><br /><ul><li>wotif.com - Glassfish & OpenMQ</li><li>www.travelmuse.com GlassFish, message queue and mysql (started by using community edition)</li><li>North american Nationwide Health Information Network - connect (NHIN- Connect)</li><li>OpenESB</li><li>ESB.SOA framework</li><li>Facebook - large mysql based system ~70million users</li></ul><br />GlassFish has same levels and structure in terms of support and licensing as MySQL<br /><br /><br /><span style="font-weight: bold;">Web Services:</span> <span style="font-weight: bold;">WS.*</span><br /><ul><li>Metro is core in GlassFish AS</li><li>Project Metro Web services stack provides high level WS stack with security, reliability etc -> .NET 3 interoperability (incorporates project tango - MS .NET interop)</li></ul> <span style="font-weight: bold;"><br />REST</span><br /><ul><li>JAX-RS JSR-311 Java API for RESTFul Web Services</li><li>Annotation based server side API</li><li>HTTP Centric</li><li>Server Side only</li><li>Servlet or SE deployment</li></ul><br />Jersey project provides implementation for JSR-311<br /><br /><span style="font-weight: bold;">Performance:</span><br /><br />Similar / faster than Weblogic and Websphere<br /><br /><br /><span style="font-weight: bold;">GlassFish V3:</span><br /><ul><li>OSGi: Apache Felix as default (origins in JSR-8)</li><li>1 sec startup</li><li>21Mb download</li><li>admin and update tool downloaded on demand</li></ul><br />Add-ons, modules available from update center:<br /><ul><li> EJB 3.1 (preview</li><li> jRuby on Rails (new WAR packaging required)</li><li> Grails (also on GFv2)</li><li> Jersey and Metro (Web services)</li><li> jMaki (AJAX)</li></ul><br /><span style="font-weight: bold;">Tools:</span><br /><ul><li> NetBeans and Eclipse</li><li> Embedded GlassFish API</li></ul><br />MicroKernel approach - modularity - base App server + on demand module loading, extensible and customizable<br /><br />("Eclipse Con" -> announces GlassFiish bundle available)<br /><br />Db connection pooling and connection (connector) pooling (JCA)<br /><br /><span style="font-weight: bold;">V3 Prelude</span><br /><ul><li>available from http://glassfish.org -> using modular (microkernel) v3 ideas with existing EE5 technologies -> <span style="font-weight: bold;">this version is supported!</span></li><li><span style="font-weight: bold;">v3 prelude is Java EE Web layer only (i.e. servlets, JSPs etc but no Enterprise beans etc)<br /></span></li></ul><br />Compile / Deploy on Change support, dynamic debug loop (netbeans & eclipse), incremental compile of all Java EE artifacts. Auto-deply of all Java EE and static artifacts<br /><br />Support for: JRuby, Ruby, Groovy, Grails, Python, jython, django, jmaki, JavaScript phobos<br /><br />Ruby / jRuby and rails can be run on 2.1 today (by packaging up dependancies), on v3 available as OSGi jRuby container<br /><br /><br />PHP<br /><ul><li>Quercis (Caucho) opensource GPL php 5 implementation in Java</li><li>War Packaging</li><li>Java Bridge</li></ul><br />V2 -> ee 5<br />V3 -> prelude with EE5 support<br />V3 -> early access is EE6 spec (but not supported)<br /><br /><br /><span style="font-weight: bold;">GF Web Stack:</span> <ul><li> Apache HTTPd</li><li> Sun web server 7 (most scalable web server - now open sourced!) optimized for multi-core CMT (chip-based Multithreaded) systems - 2x scaling vs. Apache & Tomcat</li><li> lightpd</li><li> memcached</li><li> mod_jk, perl, ruby, PHP Ruby, Python, Squid, Tomcat</li></ul><br />Current GF web stack is 1.4 (Python 2.5.2, Squid 2.6, Tomcat 5.5.27, memcached 1.2.5, mysql 5.0.67)<br /><br /><br /><span style="font-weight: bold;">GF ESB:</span><br /><ul><li>JSR 208 JBI (Java business Integration)</li><li>Plug-able integration into backbone</li><li>"Metacontainer" - add new containers within the container, extend the AS</li><li>BPEL, WS-*, XSLT, FTP, LDAP, HTTP, DB service and binding</li><li>Based on OpnESB -> http://openesb.org / community open-esb.dev.java.net/Components.html</li><li>Maybe engines and connectors to things like Corba etc</li></ul><br />What's next -> <a href="http://fuji.dev.java.net/">http://fuji.dev.java.net</a> -> OpenESB V3 - next gen of SOA<br /><br />(JBI and SCA stated as "complimentary, not conflicting")<br /><br /><br /><span style="font-weight: bold;">GF: Web Space server (project web synergy)</span><br /><ul><li>Portlet spec JSR-268 and more (social networking, communities)</li><li>OpenSSO, identify mechanisms</li><li>Compelling web UIs</li></ul><br /><span style="font-weight: bold;">GF enterprise manager:</span><br /><ul><li>Performance advisor</li><li>Alerts</li><li>JDBC pool management - automatically tunes JDBC connection pool to optimize performance etc</li></ul><br />Sailfin (Ericson contribution) telco, SIP, VOIP, Instant messaging<br /><br />dtrace etends into Apache and PHP<br /><br />Revamped PetStore 4 part tutorial - <a href="http://developer.sun.com/">developer.sun.com</a><br /><br />OpenSSO -> new concept "express builds" - milestone interim builds from Open Source community in between main supported releases<br /><br /><span style="font-weight: bold;">WhitePapers:</span><br /><br />New White-papers on GlassFish portfolio launch:<br /><ul><li>Comparison with Tomcat</li><li>Performance optimization</li><li>GF with identify and MySQL</li></ul><br />Training available in Camberly, BSG in London etc<br /><br />www.javapassion.com<br /><br /><span style="font-weight: bold;">Books:</span><br /><ul><li>GlassFish</li><li>Database-driven application development</li><li>Others available (I didn't get time to note them down)<br /></li></ul><br /><a href="http://blogs.sun.com/theaquarium">blogs.sun.com/theaquarium</a> -> god launch pad for developer information<br /><br /><a href="http://blogs.sun.com/stories">blogs.sun.com/stories</a> -> gives examples and real usage info<br /><br />Migration tools:<br /><br /><a href="http://migrate2glassfish.dev.java.net/blogs/blogs.html">migrate2glassfish.dev.java.net/blogs/blogs.html<br /></a><br />built in tools to detect and advise on code usage (for EE standards and vendor specific code dependancies)<br /><br />--<br /><br /><span style="font-weight: bold;">Examples:</span><br /><br />JavaFX mobile - answer to J2ME shortcomings<br /><br /><a href="http://www.javafx.com/">www.javafx.com</a> -> many tutorials and demos<br /><br />GlassFish profiles - Developer mode (no clustering etc) but fast start up and change deployment<br /><br /><br /><span style="font-weight: bold;">Clustering:<br /></span><br />DAS - Domain Administration server looks after a cluster, deploy to the domain administration server and it deploys to the cluster nodes.<br /><br />Session replication between cluster nodes, zero down time when switching between nodes<br /><br />install with -cluster switch<br /><br />Cluster elements run <span style="font-weight: bold;">"node-agents"</span> to talk to the <span style="font-weight: bold;">DAS</span><br /><br />Extra sections in the admin console -> shows cluster nodes<br /><br />GlassFish performance monitor - enterprise only (TBC)?<br /><br />V3 Prelude - web tier only (web apps) but fully functional<br /><br /><br />Presentation has now been published here: <a href="http://uk.sun.com/sunnews/events/2009/mar/glassfish/pdf/UK-GlassFish-Portfolio-Launch-mar09.pdf">http://uk.sun.com/sunnews/events/2009/mar/glassfish/pdf/UK-GlassFish-Portfolio-Launch-mar09.pdf</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1tag:blogger.com,1999:blog-89287579799971239.post-49641921492827786382009-03-08T01:59:00.000-08:002009-04-13T11:59:01.150-07:00Apple iPhone Development - introduction and resources<span style="font-weight: bold;">Apple iPhone Development:</span><div><br />So, it seems like everyone's doing it these days, but that's no excuse for me not to join in is it?...<br /><br />Objective-C you say, isn't that a bit like Smalltalk?<br />xCode, what's that exactly?<br />Cocoa, Nibs? what the?!?<br /><br />Well there's much to learn, but most of it seems reasonably straightforward. The Apple documentation is good, there are videos to watch and tutorials, most of these resources can be found via the Apple iPhone dev center on the Apple website. From what I've gathered so far, its quite far removed from previous mobile development I've done, such as J2ME and .NET CF.<br /><br />Armed with a new Apple Mac I'm making some notes as I venture into the unknown.<br /><br /><span style="font-weight: bold;">Firstly, here are a bunch of useful resources:</span><br /><br />iPhone Dev center:<br /><br /><a href="http://developer.apple.com/iphone/">http://developer.apple.com/iphone/</a><br /><br />iPhone Developer Program:<br /><br /><a href="http://developer.apple.com/iphone/program/">http://developer.apple.com/iphone/program/</a><br /><br />iPhone SDK:<br /><br /><a href="http://developer.apple.com/iphone/download.action?path=/iphone/iphone_sdk_for_iphone_os_2.2.1__9m2621a__final/iphone_sdk_for_iphone_os_2.2.19m2621afinal.dmg">http://developer.apple.com/iphone/download.action?path=/iphone/iphone_sdk_for_iphone_os_2.2.1__9m2621a__final/iphone_sdk_for_iphone_os_2.2.19m2621afinal.dmg<br /></a><br /><br />Objective-C:<br /><br /></div><div><a href="http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/ObjC.pdf">http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/ObjC.pdf</a><br /><br />Objective-C is an object orientated version of the C language. Specifically for the iPhone, Objective-C 2.0 is used.<br /><br />Objective-C has been influenced by Smalltalk, yes that's the OO language with all the [] in it.<br /><br />iPhone development guide:<br /><br /><a href="http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/iPhone_Development.pdf">http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/iPhone_Development.pdf</a><br /><br />First iPhone application:<br /><br /><a href="http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhone101/iPhone101.pdf">http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhone101/iPhone101.pdf<br /></a><br />The current latest version of the iPhone OS and iPhone SDK is 2.2.1 (whilst at the time of writing this 3.0 is in beta preview).<br /><br />The next version, 3.0 is to be officially launched soon, the SDK should be available before the official OS release, in theory. What's in it, what's different I don't know yet, but hopefully it will be largly compatible with the current version, whilst adding some interesting new features into the mix. Rumoured are things like the much awaited support for copy, cut and paste for example.<br /><br /><br /><span style="font-weight: bold;">HTTP and XML, web services:</span><br />Interested in hooking up an iPhone application with some web services, some means to make an HTTP request and parse XML is needed, here are a couple of resources on this:<br /><br /><br />Simple solution using some utility code:<br /><br /><a href="http://blog.atrexis.com/index.cfm/2008/7/28/iPhone--Parse-XML-to-custom-objects">http://blog.atrexis.com/index.cfm/2008/7/28/iPhone--Parse-XML-to-custom-objects</a><br /><br />A more advanced solution:<br /><br /><a href="http://code.google.com/p/touchcode/wiki/TouchXML">http://code.google.com/p/touchcode/wiki/TouchXML</a><br /><br /><br />Useful article on RESTful clients:<br /><br /><a href="http://developer.apple.com/safari/articles/creatingrestfulclients.html">http://developer.apple.com/safari/articles/creatingrestfulclients.html</a><br /><br /><br />.<br /></div>LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-65101531539315905972009-03-01T14:01:00.000-08:002009-03-02T11:52:11.569-08:00Prime factorization, a comparison between Haskell and Scala<span style="font-weight: bold;">Haskell </span>is a powerful and expressive pure lazy functional programming language with some interesting properties. <a href="http://www.haskell.org/">http://www.haskell.org/</a> Haskell is of course named after the famous logician Haskell Curry <a href="http://en.wikipedia.org/wiki/Haskell_Curry">http://en.wikipedia.org/wiki/Haskell_Curry</a> who's name can be found in both the Haskell language and the process of "currying" functions.<br /><br />By way of example and comparison the task of finding prime numbers is shown in Haskell and then its equivalent is shown in Scala.<br /><br />We can see the conciseness of Haskell and the power of lazyness in expressions of the form:<br /><br /><span style="font-family: courier new;font-family:courier new;" >[3..]</span><br /><br />which creates an infinite list of integers from 3 upwards. This seeming impossibility can be handled in a lazy functional language because the infinite list is not evaluated up front, rather the list is only evaluated when needed so the list is finite at any given point in time.<br /><br />So, in essence a lazy language is one where an expression is only evaluated when it's needed, unlike an imperative language where it's evaluated when declared.<br /><br /><br /><span style="font-weight: bold;">Haskell: prime factorization example:</span><br /><br /><pre><br />divides :: Integer -> Integer -> Bool<br />divides d n = rem n d == 0<br /><br />ld :: Integer -> Integer<br />ld n = ldf 2 n<br /><br />ldf :: Integer -> Integer -> Integer<br />ldf k n | divides k n = k<br /> | k^2 > n = n<br /> | otherwise = ldf (k+1) n<br /><br />factors :: Integer -> [Integer]<br />factors n | n < 1 = error "Invalid argument: argument must be positive"<br /> | n == 1 = []<br /> | otherwise = p : factors (div n p) where p = ld n<br /></pre><br /><br />If the above is saved in a file (called say primefactorization) and loaded into Hugs (Hugs is a Haskell interpreter shell based on Haskell 98 - <a href="http://www.haskell.org/hugs/">http://www.haskell.org/hugs/</a>) using the :l command as follows:<br /><br /><span style="font-family:courier new;">Main> :l c:\Dev\haskell\primefactorisation</span><br /><br /><br /><span style="font-weight: bold;">Scala: prime factorization example:</span><br /><br /><pre><br />package test<br /><br />object PrimeFactorisationTest {<br /><br /> def divides(d : Int, n : Int) = {<br /> (n % d) == 0<br /> }<br /><br /> def ld(n : Int) : Int = {<br /> ldf(2, n)<br /> }<br /><br /> def ldf(k : Int, n : Int) : Int = {<br /> if (divides(k, n)) k<br /> else if ((k*k) > n) n<br /> else ldf((k+1), n)<br /> }<br /><br /> def factors(n : Int) : List[Int] = n match {<br /> case 1 => Nil;<br /> case _ => {<br /> val p = ld(n)<br /> p :: factors(n / p)<br /> }<br /> }<br /><br /> def main(args : Array[String]) {<br /> if (args.length == 1)<br /> {<br /> val n = Integer.parseInt(args(0))<br /> println(factors(n))<br /> }<br /> }<br />}<br /></pre><br /><br /><span style="font-weight: bold;">Results:<br /></span><br /><br /><pre><br /><span style="font-family:courier new;">Main> factors 12343434</span><br /><span style="font-family:courier new;">[2,3,79,26041]</span><br /></pre><br /><br />Both programs produce the same output and are functionally equivalent - it's also clear to see there's a reasonably similarity in both conciseness and expressiveness of the two languages, where Haskell possibly has the slight edge in some respects such as use of the "where" construct.<br /><br /><br /><span style="font-weight: bold;">Update:</span><br /><br />Following on from the excellent comments on the Haskell version from <span style="font-weight: bold;">Don Stewart</span>, turning the code into something that can be compiled and executed natively, rather than being interpreted using Hugs, roughly involves the following steps.<br /><br />Install GHC <a href="http://www.haskell.org/ghc/">http://www.haskell.org/ghc/</a><br /><br />Rename the file to have a .hs file extension<br /><br />Add a main that can process the arguments:<br /><br /><span style="font-family: courier new;">main = do</span><br /><span style="font-family: courier new;"> [n] <- getArgs</span><br /><span style="font-family: courier new;"> print (factors (read n))</span><br /><br />add import to provide environment functions such as getArgs to the top of the file:<br /><br /><span style="font-family: courier new;">import System.Environment</span><br /><br />Compile the file:<br /><br /><span style="font-family: courier new;">$ghc --make primefactorisation.hs</span><br /><br />Run the executable:<br /><br /><span style="font-family: courier new;">$ time ./primefactorisation.exe 12343434</span><br /><span style="font-family: courier new;">[2,3,79,26041]</span><br /><br /><span style="font-family: courier new;">real 0m0.140s</span><br /><span style="font-family: courier new;">user 0m0.015s</span><br /><span style="font-family: courier new;">sys 0m0.015s</span><br /><br />and there we have it, a functional executable.<br /><br /><span style="font-weight: bold;">Don Stewart</span> also makes a good point about being able to leave out all the type information.<br /><br />In particular Haskell uses the powerful <span style="font-weight: bold;">Hindley-Milner</span> type inference algorithm to allow minimal (often zero) use of explicit type declarations.<br /><br /><a href="http://c2.com/cgi/wiki?HindleyMilnerTypeInference">http://c2.com/cgi/wiki?HindleyMilnerTypeInference<br /></a><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1tag:blogger.com,1999:blog-89287579799971239.post-36935275807861156732009-02-23T14:08:00.001-08:002009-03-15T15:53:32.160-07:00OpenSolaris, libc problem upgrading to b107Just a quick note, upgrading from b106 to 107 left me with a foobared installation. It turns out that <span style="font-weight: bold;">libc.so.1</span> ends up being an incompatible version for the Kernel.<br /><br />Luckily the fix / work around is fairly trivial :)<br /><br />On my machine it was roughly as follows:<br /><br /><span style="font-family:courier new;">beadm mount opensolaris-19 /a</span><br /><span style="font-family:courier new;">rm /a/lib/libc.so.1</span><br /><span style="font-family:courier new;">rm /a/lib/amd64/libc.so.1</span><br /><span style="font-family:courier new;">pkg -R /a fix SUNWcsl</span><br /><span style="font-family:courier new;">beadm unmount opensolaris-19</span><br /><br />Reboot into opensolaris-19<br /><br />Problem fixed!<br /><br />The bug if filed here: <a href="http://defect.opensolaris.org/bz/show_bug.cgi?id=3562">http://defect.opensolaris.org/bz/show_bug.cgi?id=3562</a><br /><br />But that's not all, I was then faced with a second problem - which turned out to be unsupported "stuff" left over in the /etc/X11/xorg.conf, in particular an "RgbPath" related config line - so this needed to be removed.<br /><br />gdm then restarted<br /><br />svcadm disable gdm<br />svcadm enable gdm<br /><br />X11 logs can also be checked for further errors:<br /><br />/var/log/Xorg.0.log<br /><br />and viola, a graphical login appears at last...<br /><br />For further details on b107 issues, see <a href="http://blogs.sun.com/alanc/entry/xorg_1_5_3_in">http://blogs.sun.com/alanc/entry/xorg_1_5_3_in</a><br /><br /><br /><span style="font-weight: bold;">Update:</span> Since these problems with 107, 108 has come out and it seems to address these issues, upgrading from 107 to 108 was completely painless and problem free!<br /><br /><br /><span style="font-weight: bold;">Additional note:</span><br /><br />Recently trying to install OpenSolaris 109 under VirtualBox 2.1.4 resulted in a frozen white screen before the graphical login. After some digging around and debugging the problem appeared to be an incompatibility with VirtualBox guest additions (GA).<br /><br />I believe the problem is captured here (as a major fault).<br /><br /><a href="http://www.virtualbox.org/ticket/3408">http://www.virtualbox.org/ticket/3408</a><br /><br />The work around / temp solution is to:<br /><br />Boot into single user command line login (edit boot grub)<br />Remove VirtualBox GA installation<br /><span style="font-style: italic;"><br />>pkginfo | grep -i box</span><br /><span style="font-style: italic;">>pkgrm SUNWvboxguest</span><br /><br />Delete xorg.conf (/etc/X11/)<br /><br /><span style="font-style: italic;">>rm /etc/X11/xorg.conf</span><br /><br />Restart GDM (svcadm restart gdm)<br /><br />Check logs:<br /><br /><span style="font-style: italic;">>tail -f /var/log/Xorg.0.log</span><br /><br />--<br /><br />To install VirtualBox Guest Additions, select "Devices -> Install Guest Additions..."<br /><br />Navigate to the installer resources (usually visible on the guest OS desktop)<br /><br /><span style="font-style: italic;">>pkgadd -d ./VBoxSolarisAdditions.pkg</span><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-54111843473461340032009-02-22T03:59:00.001-08:002009-02-22T04:23:26.040-08:00Scala, implicit conversionsToday, a small posting on the <span style="font-weight: bold;">implicit conversion</span> feature of <span style="font-weight: bold;">Scala</span>.<br /><br />Implicit conversions provide a powerful way to extend classes with new functionality, as if already built into the library or even the language itself. There are similarities with C# extension methods, but Scala's implicit conversion mechanism is more concise, flexible and maintainable.<br /><br />To define an implicit conversion in Scala, the syntax is:<br /><br /><span style="font-family:courier new;">impict def myImplicitConversionName(n: type) = new MyConversionType(n)</span><br /><br />The scenario is that you want to add some new method(s) or functionality to instances of an existing class for which may be final/sealed or where sub-classing is inappropriate or not possible / effective. Implicit conversions provide a very natural way to add functionality and to users it will appear as natural features of the language/library, no special syntax is required.<br /><br />A good example is provided on the Scala site: <a href="http://www.scala-lang.org/node/226">http://www.scala-lang.org/node/226</a><br /><br />Which is a good example because it shows exactly the reasons why you might want to extend the language or library. In this case, the type <span style="font-style: italic;">int</span> provides a good candidate for extension - to add the ! factorial function as if it was natural function of the type int.<br /><br />I wanted to expand on this example by providing a couple of examples of the same thing with further explanation.<br /><br /><span style="font-weight: bold;">Example 1:</span> explicitly defining a class that provides the extensions and using it in the implicit def<br /><br /><pre><br />object extendBuiltins2 {<br /><br />// the important bit, it says there's an implicit conversion from int to Factorizer(n : int)<br />implicit def int2fact(n: Int) = new Factorizer(n)<br /><br />def main(args : Array[String]) = {<br /><br /> // when the compiler sees this, it will first 'look for' ! method in int,<br /> // when it doesn't find it, it will look for an implicit conversion on int that provides !<br /> // which is of course exactly what we've just provided in the Factorizer class<br /> println("10! = " + (10!))<br />}<br /><br />// define ! as a method on a class that can be constructed from int - this class will<br />// provide the implicit conversion that supplied an implementation of ! on int<br />class Factorizer(n: Int) {<br /><br /> def ! = fact(n)<br />}<br /><br />// the plain old factorial function<br />def fact(n: Int): BigInt =<br /> if (n == 0) 1 else fact(n-1) * n<br />}<br /></pre><br /><br />The key line that defines the implicit conversion is this:<br /><br /><span style="font-family:courier new;">implicit def int2fact(n: Int) = new Factorizer(n)</span><br /><br />what we are saying is that there is an implicit conversion from type <span style="font-style: italic;">int </span>to type <span style="font-style: italic;">Factorizer(int)</span> - so where we have an int, if ! is called the compiler will look for ! on int and fail to find it. It will then seek an implicit conversion that can convert from int in order to provide this method ! - where it finds our implicit conversion definition that uses the Factorizer class to provide the implementation of !<br /><br />One reason this is more powerful than extension methods is that a whole class of functionality can be added to an existing class without explicitly extending all the methods individually. This has important benefits when it comes to maintenance, if the definition of the extending class changes, you get those changes automatically, you do not have to modify all the extension methods to match.<br /><br /><br /><span style="font-weight: bold;">Example 2:</span> equivalent to the above example but using an anonymous class for a more concise solution where the explicit definition of a class is of no other use.<br /><br /><pre><br />/* More concise way of adding ! as a method on int's - no explicit class definition */<br />object extendBuiltins {<br /><br />implicit def int2fact(n: Int) = new {<br /><br /> def fact(n: Int): BigInt =<br /> if (n == 0) 1 else fact(n-1) * n<br /><br /> def ! = fact(n);<br />}<br /><br />def main(args : Array[String]) = {<br /><br /> println("10! = " + (10!))<br />}<br />}<br /></pre><br /><br />This achieves the same this as example 1 but does so more concisely with the <span style="font-weight: bold;">anonymous class</span>, constructed using the convenient <span style="font-weight: bold;font-family:courier new;" >= new {} </span>syntax.<br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1tag:blogger.com,1999:blog-89287579799971239.post-35393112824574950032009-02-20T11:08:00.000-08:002009-03-02T12:06:34.333-08:00Some interesting reading material and resources...<span style="font-weight: bold;">Some interesting reading material and resources...</span><br /><br />Nothing much to see here, I just wanted to capture some links to interesting resources and reading material...<br /><br />Papers and articles on Lambdas<a href="http://library.readscheme.org/page1.html"> http://library.readscheme.org/page1.html</a><br /><br />Functional Java library - <a href="http://functionaljava.org/">http://functionaljava.org/</a><br /><br />This library brings some functional programming constructs and library functions to Java, using either Java bgga prototype compiler based on JDK 7 or a more traditional anonymous class approach using standard Java 5. Both are JRE 5 compatible.<br /><br />The Java Closures BGGA proposal<span style="text-decoration: underline;"> </span><a href="http://javac.info/">http://javac.info/</a><br /><br />.Net functional extension method library <a href="http://www.mono-project.com/Rocks">http://www.mono-project.com/Rocks</a><br /><br />Apple iPhone Dev centre - <a href="http://developer.apple.com/iphone/index.action">http://developer.apple.com/iphone/index.action</a><br /><br /><span style="font-size:100%;"><a href="http://www.iolanguage.com/">http://www.iolanguage.com/</a><br /><br /><br /></span>.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com0tag:blogger.com,1999:blog-89287579799971239.post-86245065813950727202009-02-18T11:54:00.000-08:002009-02-21T12:18:51.664-08:00Currying, some examples and comparisons between C# and ScalaI'm back again! It's been some 3 weeks since my last blog - I've been in New York for 5 days and busy either side sorting out commitments and work and home.<br /><br />So, in this posting I'd like to continue on the theme of Lamda and functional programming with some simple examples of Currying in both C# .Net (3.0+) and Scala.<br /><br />I've tried to keep the examples equivalent as closely as possible but Scala has a few different options when it comes to syntax, so the Scala version is a little longer as it delves into these extra possibilities.<br /><br /><span style="font-weight: bold;">What is currying?</span><br /><br />In a nutshell currying is "the process of reducing a function that takes multiple arguments into a series of functions that each take one argument"<br /><br />Named after Haskell Curry - <a href="http://en.wikipedia.org/wiki/Haskell_Curry">http://en.wikipedia.org/wiki/Haskell_Curry</a><br /><br />A good explanation and definition can be found here <a href="http://www.haskell.org/haskellwiki/Currying">http://www.haskell.org/haskellwiki/Currying</a><br /><br /><span style="font-weight: bold;">C# .Net example using C# 3.0+ syntax for Lamdas:</span><br /><br /><pre><br />using System;<br /><br />static class Program<br />{<br /> static void Main()<br /> {<br /> Func<int, int, int> add = (x, y) => x + y;<br /><br /> var curriedAdd = add.Curry();<br /><br /> var curriedIncrement = add.Curry()(1);<br /> var curriedDecrement = add.Curry()(-1);<br /><br /> Console.WriteLine("curriedAdd(10)(11) = " + curriedAdd(10)(11));<br /> Console.WriteLine("curriedIncrement(41) = " + curriedIncrement(41));<br /> Console.WriteLine("curriedDecrement(41) = " + curriedDecrement(41));<br /> }<br /><br /> // a simple 2 arg curry template function<br /> static Func<TArg1, Func<TArg2, TResult>> Curry<TArg1, TArg2, TResult>(this Func<TArg1, TArg2, TResult> f)<br /> {<br /> return a1 => a2 => f(a1, a2);<br /> }<br />}<br /></pre><br />Results:<br /><pre><br />curriedAdd(10)(11) = 21<br />curriedIncrement(41) = 42<br />curriedDecrement(41) = 40<br /></pre><br /><span style="font-weight: bold;">Notes:</span><br /><br /><ul><li>The use of the var keyword for implicit typing</li><li>C# does not provide implicit functions/ partial application so a Curry template function for 2 arguments has been provided explicitly.</li><li>The Curry method is defined as an extension method so it appears as-if defined on add<br /></li></ul><br />Extension Method:<br /><br /><span style="font-family:courier new;">static Func<TArg1, Func<TArg2, TResult>> Curry<TArg1, TArg2, TResult>(this Func<TArg1, TArg2, TResult> f)</span><br /><br />Take the above definition of a method, the this keyword in the (this Func...) parameter definition makes the function an extension method, so it can be used as if it were declared on the add function - to illustrate the point, without the extension syntax the Curry function could only be invoked in the regular way as follows:<br /><br /><span style="font-family:courier new;">var curriedAdd = Curry(add);</span><br /><br />As an extension method, it's valid to use the original add.Curry() or Curry(add) syntax interchangeably.<br /><br /><br /><span style="font-weight: bold;">Scala example:</span><br /><pre><br />package test;<br /><br />object Currying {<br /><br /> def main(args : Array[String]) {<br /><br /> // regular syntax function add<br /> def add(x : int, y : int) = {<br /><br /> x + y<br /> }<br /><br /> // create curried add using 1 and -1 for increment and decrement by invoking partial function (a:int, _:int):int<br /> var curriedIncrement = add(1, _ : int)<br /> var curriedDecrement = add(-1, _ : int)<br /><br /> // test funtions<br /> println("add(10, 11) = " + add(10, 11))<br /> println("curriedIncrement(41) = " + curriedIncrement(41));<br /> println("curriedDecrement(41) = " + curriedDecrement(41));<br /><br /> // curried syntax function add<br /> def add2(x : int)(y : int) = {<br /><br /> x + y<br /> }<br /><br /> // create curried functions using partial functions<br /> var curriedIncrement2 = add2(1)(_ : int)<br /> var curriedDecrement2 = add2(-1)(_ : int)<br /><br /> println("add2(10)(11) = " + add2(10)(11))<br /> println("curriedIncrement2(41) = " + curriedIncrement2(41));<br /> println("curriedDecrement2(41) = " + curriedDecrement2(41));<br /><br /> // special {} syntax<br /> val res1 = add2(10) {<br /> 11<br /> }<br /><br /> println("res1 = " + res1)<br /><br /> // more complex example<br /> val x = 1<br /> val y = 2<br /><br /> val z = add2(10) {<br /><br /> add2(20) {<br /><br /> x + y<br /> }<br /> }<br /><br /> println("z = " + z)<br /> }<br />}<br /></pre><br /><br /><span style="font-weight: bold;">Results:</span><br /><pre>add(10, 11) = 21<br />curriedIncrement(41) = 42<br />curriedDecrement(41) = 40<br />add2(10)(11) = 21<br />curriedIncrement2(41) = 42<br />curriedDecrement2(41) = 40<br />res1 = 21<br />z = 33<br /></pre><br /><span style="font-weight: bold;">Notes:</span><br /><ul><li>Scala supports f(x:int)(y:int) syntax for explicit curried functions</li><li>Scala supports implicit currying using partial application, using the placeholder _ syntax</li><li>Scala supports curried parameter in {} syntax for functions that appear to extend the language by taking parameter from the body of the call.</li></ul><br /><br /><br /><span style="font-weight:bold;">Update:<br /></span><br /><br />I realised that the way I'd defined the curried add functions in the Scala example is perhaps not as verbose or explicit as it could have been, and therefore perhaps less easy to understand or compare to the C# example. So here is another code snipped that shows a more verbose currying:<br /><br /><pre><br />object Currying {<br /><br /> def main(args : Array[String]) {<br /><br /> def add3(x : int) = {<br /><br /> (y : int) => {<br /> x + y<br /> }<br /> }<br /><br /> println("add3(1)(2) = " + add3(1)(2));<br /><br /> val res = add3(5){<br /><br /> 3<br /> }<br /><br /> println("res = " + res)<br /> }<br />}<br /></pre><br /><br />Results:<br /><br /><pre><br />add3(1)(2) = 3<br />res = 8<br /></pre><br /><br /><span style="font-weight: bold;">Resourses:</span><br /><br />Good explanation of currying in C#.Net <a href="http://diditwith.net/2007/08/15/TheArtOfCurrying.aspx">http://diditwith.net/2007/08/15/TheArtOfCurrying.aspx</a><br /><br /><br />.LouisBhttp://www.blogger.com/profile/02740188722372761051noreply@blogger.com1