Scala Geliştirme Ortamı ve Örnek Web Uygulaması

February 10, 2011

Geçen yazımda Scala programlama diline kabaca giriş yapmıştık, bu yazımda ise bir web çatısı kullanımına geçmeden önce Scala geliştirme ortamını kurmaktan ve basit bir web uygulaması nasıl yazılır bundan söz etmek istiyorum.

Bu belgeleme ile aşağıdaki teknolojilerin içermektedir.

Scala'nın Kurulumu

Scala, bilinen tüm popüler işletim sistemleriyle çalışmaktadır. Son sürümünü Scala’yı sitesinden IzPack Installer versiyonunu indirerek kurabilirsiniz. Tabii bilgisayarınızda Java JDK’nın kurulu olması gerektiğini hatırlatayım.

Simple Build Tool (sbt) Kurulumu

SBT bilindiği üzere, proje yapılandırma aracıdır. Ivy ve Maven depolarından proje bağımlılıklarını hızlıca elde edebilirsiniz. Eklenti desteği ile embedded jetty, test işlemleri gibi çeşitli ihtiyaçlarınızı karşılayabilir sizde kendi eklentilerinizi yazabilirsiniz.

SBT'nin kurulumu;

Son kararlı sürüm olan 0.7.4’ü buradan ya da projenin sitesinden en güncel sürümünü indirebilirsiniz.

Neden SBT?

SBT tamamiyle Scala diliyle yazılmıştır. Ve bağımlılık yönetiminde Maven ve Ivy’i depoları kullanır. Isterseniz manuel olarak yeni bir depo ekleyebilir yada cikartabilirsiniz. SBT’nin gelişmiş bir console arayüzü vardır. SBT komutları iki çeşittir. Bir doğal komutları, ikincisi ise pluginlerle gelen komutlar ve ikinci olarakta action diye adlandırılan plugin komutlarıdır. Bu komutların çağrısı yapılırken özel anlamlara gelen ön ekler alabilirler. Bu sayede komutlar daha güçlendirilebilir.

$ sbt help
[info] Building project HelloWeb 1.0 against Scala 2.8.1
[info]    using HelloProject with sbt 0.7.4 and Scala 2.7.7
You may execute any project action or method or one of the commands described below.
Available Commands:
   <action name> : Executes the project specified action.
   <method name> <parameter>* : Executes the project specified method.
   <processor label> <arguments> : Runs the specified processor.
   ~ <command> : Executes the project specified action or method whenever...
   < file : Executes the commands in the given file.  Each command should...
   + <command> : Executes the project specified action or method for all...
   ++<version> <command> : Changes the version of Scala building the project...
   * : Prefix for commands for managing processors.  Run '*help' for details.
   ! : Prefix for history commands.  Run '!' for history command help.
...

Sbt’nin konfigürasyon dosyası yine Scala kodları yani Trait türünde sınıflardan türetilerek yapılır. Türediği Trait sınıfına ve yüklendiği eklentilere göre projenin türü ve kullanılacak actionlar belli olur.

Yukarıda adından söz ettiğimiz bu konular makalenin sonunda yaratacağımız örnek proje ile daha iyi anlayacaksınız.

Unix ve MacOs Sistemleri için sbt.sh dosyası
java -Xmx512M -Xss2M -XX:+CMSClassUnloadingEnabled -jar `dirname $0`/sbt-launcher.jar "$@"
Windows Sistemleri için sbt.bat dosyası
set SCRIPT_DIR=%~dp0
java -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -jar "%SCRIPT_DIR%\sbt-launcher.jar" %*

Scala-IDE Kurulumu

Scala IDE projesi Eclipse platformu üzerinde geliştirilene daha çok yeni olan bir projedir. Eksikleri olsada, Eclipse sayesinde bu açıklar zamanla toparlanacaktır. Scala IDE’yi kurmak için bilgisayarınızda Eclipse’in kurulu olduğunu varsayıyorum.

Eclipse, Scala-IDE eklentisinin kurulumu için aşağıdaki video işinize yarayacaktır. Kendini eclipse sürümünüze uygun eklentinin adresine ise buradan erişebilirsiniz.

Scala İle Basit Bir Web Uygulaması Yaratmak

Proje Oluşturma

Örnek uygulama adımlarını Linux ve MacOS sistemlerinde çalışacak biçimde anlatacağım. HelloWeb isimli dizini oluşturduktan sonra dizinin içine giriyor ve sbt komutunu çalıştırıyoruz. Proje dizini ve dosyasını bulamazsa, yeni proje yaratmak isteyip istemediğimizi soruyor. Yeni proje yaratma adımları için aşağıdaki şekilde tamamladıktan sonra sbt konsolundan exit komutuyla çıkıyoruz.

$ mkdir HelloWeb &amp;&amp; cd HelloWeb
$ sbt
Project does not exist, create new project? (y/N/s) y
Name: Hello Web
Organization: Hasan Ozgan
Version [1.0]:
Scala version [2.7.7]: 2.8.1
sbt version [0.7.4]:
Getting Scala 2.7.7 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
confs: [default]
2 artifacts copied, 0 already retrieved (9911kB/35ms)
Getting org.scala-tools.sbt sbt_2.7.7 0.7.4 ...
:: retrieving :: org.scala-tools.sbt#boot-app
confs: [default]
15 artifacts copied, 0 already retrieved (4096kB/71ms)
[success] Successfully initialized directory structure.
Getting Scala 2.8.1 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
confs: [default]
2 artifacts copied, 0 already retrieved (15118kB/72ms)
[info] Building project Hello Web 1.0 against Scala 2.8.1
[info]    using sbt.DefaultProject with sbt 0.7.4 and Scala 2.7.7
> exit

Projeyi yarattığımızda aşağıdaki gibi bir dizin ağacı göreceksiniz. Bu dizin ağacında project isimli dizinde proje yapılandırma işlemlerimizi yapıyoruz. Projemizin kaynak kodları ise src/main/scala dizinin altında yazıyoruz. Henüz uygulamamız web uygulaması olarak yapılandırılmadığı için src/main/webapp dizini mevcut değil. Yazının ilerleyen bölümlerinde bu dizini ve konfigürasyonları elle yapılandıracağız. :)

HelloWeb$ tree
   .
   ├── lib
   ├── project
   │   ├── boot
   │   └── build.properties
   ├── src
   │   ├── main
   │   │   ├── resources
   │   │   └── scala
   │   └── test
   │       ├── resources
   │       └── scala
   └── target
Projenin Yapılandırılması

Şimdi örnek web uygulamamız için projemizi yapılandırmaya başlayalım. Sbt kendini çalıştırdığında project/build/*.scala dizini altında BasicScalaProject abstract sınıfından türemiş bir sınıf arar. Yapılandırma işlemleri bu sınıfın içinde olur.

Şimdi gelin bizde böyle bir sınıf tanımı yapalım.

HelloWeb$ mkdir build
HelloWeb/build$ vim HelloProject.scala
import sbt._

class HelloProject(info: ProjectInfo) extends DefaultWebProject(info)
{
    override def libraryDependencies = Set(
        "javax.servlet" % "servlet-api" % "2.5" % "provided"
        "org.mortbay.jetty" % "jetty" % "6.1.22" % "test-&gt;default"
    ) ++ super.libraryDependencies
}

project/build/HelloProject.scala

Şimdi uygulamamızı yazmaya geçmeden önce projemizi eclipse taşıyalım. Bunun için, Eclipsify isimli sbt eklentisini kurmamız gerekiyor. SBT projesine eklentileri tanımlamakta çok kolay. Öncelikle dizinini eklememiz gerekiyor.

HelloWeb$ mkdir -p project/plugins
HelloWeb/project/plugins$ vim HelloPlugins.scala
import sbt._

class HelloPlugins(info: ProjectInfo) extends PluginDefinition(info) {
    lazy val eclipse = "de.element34" % "sbt-eclipsify" % "0.7.0"
}

project/plugins/HelloPlugins.scala

Son olarakta HelloProject.scala sınıfımıza eklentiyi tanımlamamız gerekiyor. Sınıfımız aşağıdakine benzemeli.

import sbt._
import de.element34.sbteclipsify._

class HelloProject(info: ProjectInfo) extends DefaultWebProject(info) with Eclipsify
{
    override def libraryDependencies = Set(
        "javax.servlet" % "servlet-api" % "2.5" % "provided"
        "org.mortbay.jetty" % "jetty" % "6.1.22" % "test-&gt;default"
    ) ++ super.libraryDependencies
}

Artık uygulamamızı yazmaya hazırız. Yapmamız gereken son bir işlem var. SBT projemizi Eclipse’in anlayacağı hale sokmak. Bunun için önce javax.servlet ve jetty bağımlılıklarımızı güncellememiz gerekiyor. Bunu yapmamızı sağlayan komut ise update. Bu işlemi yaptıksan sonra eclipse isimli yeni action görmeniz gerekiyor.

sbt update
[info] Recompiling plugin definition...
[info] 	  Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed.
[info]
[info] Updating plugins...
[info] downloading http://scala-tools.org/repo-releases/de/element34/sbt-eclipsify/0.7.0/sbt-eclipsify-0.7.0.jar ...

sbt actions komutunda listenen action listesinin içinde eclipse’ei görmeniz gerekiyor. Eğer görüyorsanız eclipse proje dosyasını oluşturmak için;

HelloWeb$ sbt eclipse
[info] Building project HelloWorld 1.0 against Scala 2.8.1
[info]    using Project with sbt 0.7.4 and Scala 2.7.7
[info]
[info] == eclipse ==
[info] Creating eclipse project...
[info] == eclipse ==
[success] Successful.
[info]
[info] Total time: 0 s, completed Feb 9, 2011 5:59:41 PM
[info]
[info] Total session time: 1 s, completed Feb 9, 2011 5:59:41 PM
[success] Build completed successfully.

Artık işlemi tamamladık. Şimdi Eclipse açarak, projeyi import edebilirsiniz.

HelloWeb Project Import  

Son olarak Eclipse’ten SBT’yi çalıştırmak için External Tool Configuration seçeneğinden tanımlamamız gerekiyor. Aşağıda örnek ayarlara ait ekran görüntüsünü bulabilirsiniz.

Artık web uygulamamızı yazmaya başlayabiliriz.

Scala Servlet

Scala’nın java mimarileriyle çalışabildiğinden daha önce söz etmiştim. Bu nedenle bir scala web uygulaması yazmak, bir java web uygulaması yazmaktan pek farklı değildir. Scala’da servlet sınıfları kullanılarak yazılabilir. Aşağıda basit bir servlet sınıfı bulunmaktadır. Scala dilinde XML aynı bir String gibi bir tiptir. Örnek scala kodumuzun java’dan tek farkı HTML tipinin parametre olarak verilebilmesidir.

package com.hasanozgan.web

import java.io._
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}

class HelloServlet extends HttpServlet
{
    override def doGet(req: HttpServletRequest, res: HttpServletResponse)
    {    
        doRequest(req, res) 
    }    

    override def doPost(req: HttpServletRequest, res: HttpServletResponse)
    {    
        doRequest(req, res) 
    }    

    private def doRequest(req: HttpServletRequest, res: HttpServletResponse)
    {    
        res.getWriter().print(<html>
              <head>
                <title>Hello World</title>
              </head>
              <body>
                <h1>Hello from Scala!</h1>
              </body>
            </html>)
    }    
}

src/main/scala/com/hasanozgan/web/HelloServlet.scala

Şimdi wepapp ve WEB-INF dizinlerini yarartmaya ve webapp/WEB-INF/web.xml dosyasını oluşturmamız gerekiyor. Aşağıdaki örnek bir web.xml dosyası mevcut.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   version="2.5">

  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>com.hasanozgan.web.HelloServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/index</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>index</welcome-file>
  </welcome-file-list>

</web-app>

src/main/webapp/WEB-INF/web.xml

Uygulamayı çalıştırmak için ise sbt ~jetty-run komutunu çalıştırmamız yeterlidir.

HelloWeb$ sbt ~jetty-run

Not: sbt ~jetty-run komutu ile sbt jetty-run komutu arasında şöyle bir fark bulunur. Eğer bir komut “~” işareti ile başlarsa projenin dosyalarında bir değişiklik olursa proje tekrar derlenir.

Scala Server Pages (Scalate)

Scala dünyasında Quick & Dirty birşeyler yapmak isteyenler için JSP’ye benzer bir template engine kütüphanesi mevcut. Scalate (Scala Template) isimli bu proje gerçktende çok başarılı template modelleri ile geliyor. Bu modellerden benim tercihim SSP yani Scala Server Pages modeli. Zevkinize göre diğer modellere de göz atabilirsiniz.

  1. Önce sbt proje sınıfımıza(HelloProject.scala) scalate için gerekli olan tanımları("org.fusesource.scalate" % "scalate-core" % "1.2") yapmamız gerekiyor. Ayrıca, jetty'nin portunu nasıl değiştirebileceğimizide görelim.
    import sbt._
    
    class HelloProject(info: ProjectInfo) extends DefaultWebProject(info)
    {
         val jettyPort = 8090
    
        override def libraryDependencies = Set(
            "org.fusesource.scalate" % "scalate-core" % "1.2",
            "javax.servlet" % "servlet-api" % "2.5" % "provided"
            "org.mortbay.jetty" % "jetty" % "6.1.22" % "test-&gt;default"
        ) ++ super.libraryDependencies
    }
    Proje ile değişiklikler yaptıktan sonra sbt update komutunu çalıştırmayı unutmayın.
  2. Şimdi web.xml dosyamızda Servlet Filter'ı tanımlamamız gerekiyor.
      <!-- START: Scalate config -->
      <servlet>
        <servlet-name>TemplateEngineFilter</servlet-name>
        <servlet-class>org.fusesource.scalate.servlet.TemplateEngineServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>TemplateEngineFilter</servlet-name>
        <url-pattern>*.ssp</url-pattern>
      </servlet-mapping>
      <!-- END: Scalate config -->
  3. Şimdi son olarak index.ssp dosyamızı yazalım. SSP ile ilgili daha detaylı örnek arayanlar scalate'in github hesabından örnek kodları inceleyebilir.
    <html>
        <head>
        <title>Scala Server Pages</title>
        </head>
        <body>
    <%
        var username: String = "";
        if (request.getMethod().equals("POST")) {
            username = request.getParameter("username")
            out.println("Hello, "+username);
        }    
    %>
            <form method="post">
                <input type="text" name="username" value="${username}"/>
                <input type="submit" value="Ok" />
            </form>
        </body>
    </html>

Böylece bir Scala Server Page koduda yazmış olduk.

Kaynak Kod

Örnek uygulamanın kaynak kodlarına aşağıdaki linkten erişebilirsiniz. Scala Web Uygulaması Kaynak Kodları

Özetleyecek olursak, Sbt ile Scala projesi yaratma ve basit web uygulamarı yazmayı adımlarını görmüş olduk. Benim için bu yazı gerçekten yorucu ve uzun oldu, umarım işinize yaramıştır. Bir sonraki yazımızda ise veritabanı işlemlerinden söz etmeyi planlıyorum. RDBMS (mySQL) ve NOSQL (mongoDB) örnekleri içeren bir yazı olacak. Bu hafta veritabanı işlemlerine de bir giriş yaptıktan sonra, Lift Web Framework ile adım adım örnek bir web uygulaması geliştireceğiz.. (Benim aklımdan Grupon yada Hacker News klonu yapmak geçiyor. Eğer başka bir öneriniz varsa lütfen benimle paylaşın)