2013年9月8日日曜日

Salesforce Developer Conference Tokyo 2013 (Mini Hackレポート)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Salesforce.comの開発者向けイベント、Salesforce Developer Conference Tokyo 2013行ってきました。

去年のCloudforceでもあったMini Hack、今回は豪華賞品を揃えて全4問で再登場したの挑戦しました。なんと4問提出で、抽選で1名なんとDreamforceツアーご招待。

4問の課題は以下の内容:

とりあえず簡単そうなものから…と思って課題流し読みして、Aからやろうと思ったらTreaure Dataのアドオン追加がなぜかエラー…。Kからやることに。

課題K「Heroku Platform APIをつかってHerokuを操作しよう!」

要は、最近公開されたPlatform APIを試してみてね、という課題Platform APIのチュートリアル通りにコマンドラインからcurlでAPIの動作を確認すればOK。
一部、チュートリアルのコマンド例そのままだとContent-Type: application/jsonヘッダが足りなくてエラー出てたので報告しときました。
Heroku使った事あれば簡単すぎますね。

まだTreasure Dataのアドオンが追加できなかったので次はH。

課題H「Mobileアプリケーションを作ってみよう!」

こちらも数ヶ月前にリリースされたMobile Packを試してみてね、という課題。Mobile Packを使用して取引先の一覧を表示するモバイル用ページを作ればOK。
jQuery mobile, AngularJS, Backbone.js, Knockout, appery.io, Sencha, Xamarin, Codiqaと多数のフレームワークに対応してる様です(半分くらい知らない)。
とりあえず普段使っているAngularJSでやろうとサンプルコードを落としてきて動かしてみるが、app.jsとかを静的リソースに突っ込むのが面倒そうで、jQuery mobileに変更(@a_kurataniさんがjQuery mobileでやったら簡単だったと言ってたのでw)。
サンプルコードの取引先責任者の一覧表示するVisualforce Pageを覗いてみるとJSに直にSOQLが…。オブジェクト名と項目名だけ変えておしまいですね。

@mino0123さんのツイートを見て、アドオン追加が復活してるっぽかったのでAを再開。

課題A「Treasure Dataアドオンを使ってみよう!」

Treasure DataのHerokuアドオンを試してみてね、という課題
とりあえず課題シートの指示通りにデモアプリをgithubからcloneして、コマンドラインからアドオン追加、プラグイン追加、デプロイをしてみます。
デモアプリをブラウザで開いても、Hello World!が出るだけで動きが分からないのでソースを追ってみると、アクセスの都度裏でTDにログを送る様です。
「サンプルアプリを修正して画面の表示を変更してください」って画面の修正だけで本当にいいのか気になりながら、変更するところはタイトルくらいしか無かったのでHello World! をHoge Hoge! みたいに書き換えて聞いてみたらこれでOKw(TD関係ないじゃん)
ちなみにRubyを全然書いたことがないので初めて.erbファイルをさわった(デモアプリはsinatra)。

3問でMBA狙いにしようかと思ったけど時間あったから4問目も挑戦。

課題C「オフラインHack - SmartStore」

Mobile SDKを使ってオフライン対応のアプリを作れ、という課題と勝手に解釈。
SmartSyncがBackbone.js使われてるとか基調講演で聞いたので、ちょっと難易度高いかなーと思って思い込んで避けてたやつ。
Mobile SDKは前に落として試してたけど、念のため最新版をgit pull。
iOS版のサンプルアプリをXcodeからとりあえず動かしてみて、問題を良く読んでみると…「提出方法:サンプルの動作が画面で確認できたら、お声掛けください」
始める前に、終わってた。
@yonet77さんがサンプルコードでビルドエラーが…て困ってたのでちょっと見てみたら、最近iOS7対応したときに見覚えのある定数が。github上のmasterがすでにiOS7対応されてて、β版Xcodeじゃないとヘッダ足りなくて動かないので、β版Xcode5持ってない場合は古いリビジョン取り直さないとダメという罠

4問解いておいて、Dreamforceにするか、MBAにするかギリギリまで迷ったけど、@yonet77さんがDreamforceに1人目で申し込んだので、このままだと確定で面白くないなーということで同じくDreamforceに申し込んだら、なんと抽選当たってしまいました!

Developer Conference参加自体も直前で決めたのに、なんか申し訳ない…

最後に、傾向と対策

  • なんか難しそうだけど課題の意図はとりあえず手を動かしてさわってみてね、という所だと思うのでチュートリアルレベル。とにかくやってみる
  • git, herokuは使えて当たり前? 環境は整えておく
  • ノートパソコンの電源アダプタは持ってくる(電池切れた…て人がちらほら)

課題カードが無くなるの早かった割には、参加者少なかったんじゃないかな…
あと提出方法、応募方法が分かりにくかったという声も…
SDUG(Salesforce Developer User Group)に参加してると最新情報に強くなれますよー、とちょっと宣伝で締めにします。



2012年12月4日火曜日

[force.com] CSV添付のメールをスケジューリングして送る

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

とある案件で毎日CSVをメールに添付して送る要件があり、実装できるまでの顛末のメモです。 問題は、添付するCSVの文字コードがShift_JIS、改行コードがCRLFじゃないといけないこと…

1. まずはControllerとVisualforceでSJISのCSVを吐き出してみる

public class CSVController {
    public String getCRLF(){return '\r\n';}
    public List<Account> accounts{get;set;}
    public CSVController() {
       accounts = [select id, name from Account];
    }
 }

{!a.id},{!a.name}{!CRLF}

こんな感じで、/apex/CSVPage でSJISのCSVがダウンロードできた。簡単すぎる。

2. メール添付して送ってみる

スケジュールApexでスケジューリングする予定なのでScheduableインタフェースを実装して、こんな感じで。

global class CSVMail implements Schedulable {
    global void execute(SchedulableContext sc) {
        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        msg.setSubject('テスト');
        msg.setPlainTextBody('テスト');
        msg.setToAddresses(new String[]{'pomu0325@gmail.com'});
       
        Messaging.EmailFileAttachment att = new Messaging.EmailFileAttachment();
        att.setFileName('テスト.csv');
       
        // 添付CSVをVisualforceページから読み込む
        PageReference page = new PageReference('/apex/CSVPage');
        att.setBody(page.getContent());
        msg.setFileAttachments(new Messaging.EmailFileAttachment[]{att});

        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
    }
}

開発者コンソールで、new CSVMail().execute(null); とかすればメール送信成功! あとはスケジュール設定するだけと思って「Apexをスケジュール」しても、エラーで送られないんですね…

PageReferenceのリファレンス見てみると、「This method can't be used in: … Scheduled Apex …」って使えないじゃん…どうしよう。

3. 外部のサーバで文字コードだけ変換する

Apexで文字コード変換するのが簡単にはいかなさそうなので…外部サーバで文字コード変換する為だけのapiの様なものを置いて、コールアウトで使ってみる作戦。

ScalaのUnfilteredてフレームワークで、こんな感じでデプロイしてみた。
※自分は某G社のクラウドに置きましたがherokuに置くとかいいですね!

  object UtilPlan {
    def intent = Intent {
      case r @ POST(Path("/utils/nkf")) & QueryParams(p) =>
        val encoding = p("encoding").headOption getOrElse "MS932"
        val payload = new String(Body.bytes(r), "utf-8")
        
        Ok ~> ResponseBytes(payload.getBytes(encoding))
    }
  }

これを使って、Apex Classはこんな感じに。 実行前に「セキュリティのコントロール>リモートサイトの設定」で外部サーバのURLの追加も忘れずに。

global class CSVMail implements Schedulable {
    global void execute(SchedulableContext sc) {
        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        msg.setSubject('テスト');
        msg.setPlainTextBody('テスト');
        msg.setToAddresses(new String[]{'pomu0325@gmail.com'});
       
        Messaging.EmailFileAttachment att = new Messaging.EmailFileAttachment();
        att.setFileName('テスト.csv');
       
        /*
        // 添付CSVをVisualforceページから読み込む
        PageReference page = new PageReference('/apex/CSVPage');
        att.setBody(page.getContent());
        */
        // 添付CSVを文字列で生成して外部サーバで文字コード変換
        String csv = CSVMail.csv([select id, name from Account]);
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://ひみつ/utils/nkf');
        req.setMethod('POST');
        req.setBody(csv);

        Http h = new Http();
        HttpResponse res = h.send(req);
        att.setBody(res.getBodyAsBlob());
       
        msg.setFileAttachments(new Messaging.EmailFileAttachment[]{att});
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
    }
   
    private static String csv(List<Account> accounts) {
        String csv = '';
        for (Account a : accounts) {
            csv += a.id + ',' + a.name + '\r\n';
        }
        return csv;
    }
}

これもまた、開発者コンソール等からの実行だとOKだけど、スケジュールするとコールアウトがダメ… と思ったけど@future(callout=true)を付ければ非同期実行でコールアウト呼べることが判明したので@futureなメソッドにメール送信の処理を移動して完成!

global class CSVMail implements Schedulable {
    global void execute(SchedulableContext sc) {
        CSVMail.sendCSV();
    }
   
    @future(callout=true)
    private static void sendCSV() {

        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        msg.setSubject('テスト');
        msg.setPlainTextBody('テスト');
        msg.setToAddresses(new String[]{'pomu0325@gmail.com'});
       
        Messaging.EmailFileAttachment att = new Messaging.EmailFileAttachment();
        att.setFileName('テスト.csv');
       
        /*
        // 添付CSVをVisualforceページから読み込む
        PageReference page = new PageReference('/apex/CSVPage');
        att.setBody(page.getContent());
        */
        // 添付CSVを文字列で生成して外部サーバで文字コード変換
        String csv = CSVMail.csv([select id, name from Account]);
        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://ひみつ/utils/nkf');
        req.setMethod('POST');
        req.setBody(csv);

        Http h = new Http();
        HttpResponse res = h.send(req);
        att.setBody(res.getBodyAsBlob());
       
        msg.setFileAttachments(new Messaging.EmailFileAttachment[]{att});
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{msg});
    }
   
    private static String csv(List<Account> accounts) {
        String csv = '';
        for (Account a : accounts) {
            csv += a.id + ',' + a.name + '\r\n';
        }
        return csv;
    }
}

2011年12月18日日曜日

Titanium Salesforce module(SalesForce Toolkit for Appcelerator)の使い方 (2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
前回のサンプルアプリをちょっと時間が経ってから動かしてみると、

[ERROR] In the error handler looking for a 401, and have a 401

[ERROR] Handleing the 401 error...

とかエラーが出てしまい動きません…

force.comからOAuth2で取得したaccess tokenには有効期限があるのでrefresh tokenを使って再度取得する必要があるのですが…そこが動作していないようです。
force.comのOAuthについて詳しくはこちらで

エラーのコールバックも呼んでくれないので有効期限切れたかどうかも検出できず…

なんとかhackできないかと、こんな感じでモジュールの中身をダンプしてみます。

var FDC = require('com.salesforce');
for (var i in FDC.ForceOAuth) {
 Ti.API.debug(i + ':' + FDC.ForceOAuth[i]);
}

最終的にREST APIの呼び出しはここに来るようです。
[DEBUG] makeRestCall:function (path, callback, error, method, payload, retry) {var restUrl=Ti.Network.decodeURIComponent(fa.instanceUrl)+'/services/data'+path;var xhr=Ti.Network.createHTTPClient();xhr.onload=function(){Ti.API.info("REST Response: "+this.responseText);var data="";if(this.responseText){data=this.responseText;}

callback(data);};xhr.onerror=function(e){Ti.API.error("XHR, error handler..."+"\nDbDotCom.REST.OAuth.refreshToken: "+fa.refreshToken+"\nretry: "+retry+"\n e: "+e.error+"\nXHR status: "+this.status);if(!fa.refreshToken||retry){error(e.error);}else{Ti.API.error("In the error handler looking for a 401, and have a "+xhr.status);if(xhr.status===401){Ti.API.error("Handleing the 401 error...");exports.refreshAccessToken(function(oauthResponse){Ti.API.error("Refresh response... "+oauthResponse);fa.makeRestCall(path,callback,error,method,payload,true);},error);}else{Ti.API.error("Not a 401 error, re-throwing...");error(e);}}};if(fa.usePostBin===true){restUrl="http://www.postbin.org/135onm5";}

xhr.open(method||"GET",restUrl,true)

Ti.API.info("Rest url: "+restUrl);xhr.setRequestHeader("Authorization","OAuth "+Ti.Network.decodeURIComponent(fa.accessToken));xhr.setRequestHeader("Content-Type","application/json");xhr.send(payload);}

出てるログから、exports.refreshAccessToken()の呼び出しの中でエラーが起きてコールバックまで戻って来ないようです。

よく考えたら、OAuth2のrefresh tokenによるaccess token再取得時にはclient secretが必要なはずなのに、モジュールのパラメータなどでどこにもセットしていないのでrefreshできるわけないですね… 未実装なんでしょうか?
※追記:secret要らない仕様に変わってました
ダンプしたソースを参考に、こんな感じでhackしてみました。
※モジュール内で定義されてるobjectのプロパティは動的に書き換えられない?&スコープ的にアクセスできない変数があったので結構無理矢理

使い方は、requireした後にこのファイルをincludeしてパッチを当て、ForceOAuthの代わりにForceOAuth2を使うようにします。ForceOAuth2.openのパラメータにはclient idとclient secretを渡す様にします。

var FDC = require('com.salesforce');
Ti.include('fdc-patch.js');
FDC.ForceOAuth2.open('CLIENT_ID');

パッチしたポイントは2つ。refreshAccessTokenをclient secretを使用して動作する様にしたのと、REST APIのパスの固定部分に /data が含まれていたのを /apexrest が呼べる様に /services までとしたこと。

Winter '12でリリースされたApex RESTを使って公開したAPIのURLは、$instance_url/services/apexrest/... となるので、FDC.ForceOAuth2.makeRestCall('/apexrest/myapi', callback) の様な感じで使える様になります。

marketplaceのモジュールのページには、"This toolkit is maintained by the community and sponsored by salesforce.com. Salesforce.com does not officially support this product."とか書いてあるんですが、パッチとか提供したい場合どこに連絡すればいいんでしょうか… githubとかにソース上がってればforkするのに…

この記事はForce.com Advent Calendar 2011に参加しています。

2011年12月8日木曜日

Titanium Salesforce module(SalesForce Toolkit for Appcelerator)の使い方

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
最近、Titanium Mobileでforce.comのREST APIを使用したiPhoneアプリを作ってます。

Titanium Mobileについての基本的な知識やTitanium Studioの使い方はある程度知ってる前提で書いているので、Titaniumについて知りたい方は「Titanium Mobileで作る! iPhone/Androidアプリ」などを参考にどうぞ。

Titaniumにはmarketplaceがあり、ソフトウェア部品としてのモジュールや、アプリのテンプレートなどをダウンロードできます(有償のもアリ)。
うまいこと目的に合ったモジュールを見つけて利用すれば開発スピードは向上する…はず…

Salesforce用のモジュールも用意されているので、今回の開発にはこれを利用しました。が、ドキュメントが大して無かったりで取っ掛かり苦労したのでメモとして残しておきます。
今回は、モジュールを使うまでの準備と、サンプルコードの実行まで。

2011年9月20日火曜日

foursquare global hackathon @ Tokyo

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
NYC, SF, Paris, Tokyoで同時開催のfoursquare global hackathon、東京会場のオーガナイザ兼参加者として9/17-18の2日間約42時間ぶっつづけで楽しんできました。

東京会場では参加者15名、応募作品9と他会場と比べて少ない数字でしたが、みんなでワイワイおやつ食べたり深夜居残り組はみんなで銭湯行ったり、いい雰囲気でした。
NYC,SF,Parisの中継映像をスクリーンに映して、音声無しながらもParisがエッフェル塔切り抜いたのカメラの前に貼って遊んでたのに東京タワーで対抗?してみたりw
Togetterまとめ

いきなりですが東京会場内での作品の投票結果発表!
日本時間9/23の正午まで、http://fshackathon.appspot.com/で一般投票が行われているので気に入った作品にぜひ投票をお願いします(何作品でも投票できます)!

1位(会場得票数4): photosquare
作者:中継カメラ設置等いろいろ手伝ってくれた@koogawaさん
内容:近くのvenueに投稿されてる写真をスライドショー表示してくれるiPhone/iPad用アプリ。アプリ審査があるのでまだダウンロードできませんが、http://twitvideo.jp/06TpCから映像見ることができます。
投票する

2位(会場得票数3):The Journalist
作者:今回素晴らしい会場を提供してくださったGaiaXの@aomushi510さんと、直前に@aomushi510さんに誘われて急遽参加のTomoyuki Hisadaさんのチーム
内容:4sqのチェックイン履歴を使用して、自分の行った場所の記事を投稿できる、ソーシャルニュース的なサービス。新聞的なデザインや、細かいところの動きがよくできていて完成度高くてびっくり!
http://journalist.azu.sh/で見れる…はずが残念ながら今エラー出てます…
投票する

同着2位(会場得票数3):4sqlist(仮)
作者:pomu0325(すいません自分です。)
内容:サブベニュー(駅のホームとか、モール内の店舗とか)をグループ化して探しやすくするiPhone/iPad用WEBアプリ。時間が無くて最低限の機能しか作り込めませんでした… 同じアイデアで作り始めた@ikawamotoさんとは違い、手動でサブベニューの情報を編集するアプローチです。http://4sqlist.appspot.com/
投票する

以下、順不動での掲載です。

チーム名:curly
作者:@takochuuさん、@sunny_510さんのチーム
内容:venue毎に、そこにチェックインした人のつぶやきが見えたりランキングが見れたりするサービス。デザインもよくまとまってましたが、公開はまだ…かな?
投票する

Packed Venues
作者:大阪から来てくれた@ikawamotoさん
内容:住所が同じベニューをまとめて表示するiPhoneアプリ。動かしているところの動画はこちら。住所表記のブレが解決できれば自動でまとめられるアプローチの方がいいですね!
投票する

Squarecount
作者:meetup主催等いつも手伝ってくれてる@jayjpn
内容:4sqへのチェックイン回数を表示するだけw。エンジニアじゃないのに締め切りぎりぎりまで頑張ってました。http://squarecount.appspot.com/index.html
投票する

4sq Scouter
作者:自分と同じく携帯用4sq「じゃぽすく」を作っている@jpfoursquareさん
内容:スカウターと言ったらおなじみ、例のアレ風に「強さ」を数値化して表示してくれます。数値には、「複雑な足し算」が使用されているとのことですw http://scouter.jpfoursquare.com/から試せます。
投票する

fourSquare PopUp Utility
作者:The Journalistもチームメンバーで作っているTomoyuki Hisadaさん
内容:4sqのユーザやvenueの情報をマウスオーバーで表示してくれるjsライブラリ。ページ内のfoursquareへのリンクを自動で変換してくれるみたいです。twitter anywhereの4sq版、と言えば分かる人には分かる。使い方等
投票する

Complete Japanese fried chicken delis in MusashiKoyama
作者:@Suger1008 さん
内容:むさこ(武蔵小山)の唐揚げ屋さんを制覇! むさこ愛にあふれるスマートフォン用アプリをTitanium Mobileで作られていました。公開はまだですが解説等はこちら
投票する

応募があったのは以上9作品ですが、他にも時間が足りなかったり、既に作っているものを4sq対応したりと各自ガリガリがんばっていました。

最後に、深夜含め2日連続と無理な条件にも関わらずすてきな会場を提供してくださった、ガイアックスさん、本当にありがとうございました!!!
ハッカソンなどのイベントでよく会場提供をしているそうなので、またお邪魔させていただきます!

2011年3月29日火曜日

[Lift] 画像ファイルにjsessionidを付けない

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
takedasoftさんがUrl Rewrite Filterを使った方法を書いてましたが、Boot.scalaでLiftRule.urlDecorateにルール追加するだけで簡単にできたのでメモ。

val ImgPtn = """(.*\.(?:png|gif|jpg));jsessionid=.+""".r
LiftRules.urlDecorate.append {
  case ImgPtn(url) => url
}

※Lift 2.2からデフォルトではjsessionid付かなくなったのはここに書いてある通りです。

2011年3月22日火曜日

[Scala] sbt jetty-runでhttpsを使用したい

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

方法1: カスタムjetty.xmlを使う

sbt標準だとjetty.xmlを1から書けばOK。
override def jettyConfiguration = new CustomJettyConfiguration {
  override def jettyConfigurationXML = List("/path/to/jetty.xml")
}

この方法だとjetty.xmlにConnectorとかHandlerとか全部自分で書かないといけないので面倒…
参考:jetty.xmlのリファレンス

方法2: sbtにちょっと手を入れてjetty設定用のhookを使う

sbtのソースをcheckoutしてhookが設定できるようにする


参考:Build - simple-build-tool -

sbtのソースをcheckout
$ git clone git://github.com/harrah/xsbt.git
$ cd xsbt

変更したのは下の2行だけ。jetty-runが呼ばれてデフォルトのhttpポートのConnectorの設定直後にcallbackで設定した関数が呼ばれるようにする。
diff --git a/sbt/src/main/scala/sbt/WebApp.scala b/sbt/src/main/scala/sbt/WebApp.scala
index f5a3d09..997294e 100644
--- a/sbt/src/main/scala/sbt/WebApp.scala
+++ b/sbt/src/main/scala/sbt/WebApp.scala
@@ -105,6 +105,8 @@ trait DefaultJettyConfiguration extends JettyConfiguration
        def parentLoader: ClassLoader
        def jettyEnv: Option[File]
        def webDefaultXml: Option[File]
+
+       def callback: Option[AnyRef => Any] = None
 }
 abstract class CustomJettyConfiguration extends JettyConfiguration
 {
diff --git a/sbt/src/main/scala/sbt/jetty/LazyJettyRun.scala.templ b/sbt/src/main/scala/sbt/jetty/LazyJettyRun.scala.templ
index 263afa6..4ca4b0e 100644
--- a/sbt/src/main/scala/sbt/jetty/LazyJettyRun.scala.templ
+++ b/sbt/src/main/scala/sbt/jetty/LazyJettyRun.scala.templ
@@ -54,6 +54,7 @@ private object LazyJettyRun${jetty.version} extends JettyRun
                                case c: DefaultJettyConfiguration =>
                                        import c._
                                        configureDefaultConnector(server, port)
+                                       c.callback.foreach(_(server))
                                        val webapp = new WebAppContext(war.absolutePath, contextPath)
                                        webDefaultXml.foreach{webDefaultXml:File => webapp.setDefaultsDescriptor(webDefaultXml.toString)}

sbtのビルド

$ sbt update generate-loader-compat proguard "project Simple Build Tool" publish-local
※generate-loader-compatしないとjetty6用のクラスが一部生成されなかった。(jettyは6->7でパッケージ名が変わったので、sbtのソースではテンプレート化して6,7,7.2用のscalaソースが吐かれるようになってる

ssl用証明書の準備

JDKのkeytoolを使用。とりあえずオレオレ証明書で。
$ keytool -keystore src/test/resources/keystore -alias jetty -genkey -keyalg RSA
$ keytool -selfcert -validity 1024 -keystore src/test/resources/keystore -alias jetty
※keystoreのパスワードを聞かれるので入力します

sbt プロジェクト側の準備

build.propertiesの sbt.version=0.7.5.RC0 にしてsbt実行、先に標準の0.7.5.RC0を入れておく。

ビルドしたsbt/target/scala_2.7.7/sbt_2.7.7-0.7.5.RC0.jar をプロジェクトのproject/boot/scala-2.7.7/org.scala-tools.sbt/sbt/0.7.5.RC0/sbt_2.7.7-0.7.5.RC0.jar に上書き。

project/build/MyProject.scala の設定。callbackでjettyのServerインスタンスにSslSocketConnectorを追加。ClassLoaderが違うので普通に書くとClassCastExceptionが発生するのでリフレクションで。
  override def jettyConfiguration: JettyConfiguration =
    new DefaultJettyConfiguration {
      def classpath = jettyRunClasspath
      def jettyClasspath = MyProject.this.jettyClasspath
      def war = jettyWebappPath
      def contextPath = jettyContextPath
      def classpathName = "test"
      def parentLoader = buildScalaInstance.loader
      def scanDirectories = Path.getFiles(MyProject.this.scanDirectories).toSeq
      def scanInterval = MyProject.this.scanInterval
      def port = jettyPort
      def log = MyProject.this.log
      def jettyEnv = jettyEnvXml
      def webDefaultXml = jettyWebDefaultXml
      override def callback = Some((server: AnyRef) =>  {
        val cl = server.getClass.getClassLoader
        val ssl = cl.loadClass("org.mortbay.jetty.security.SslSocketConnector").newInstance.asInstanceOf[{
          def setPort(p: Int): Unit
          def setMaxIdleTime(t: Int): Unit
          def setKeystore(s: String): Unit
          def setPassword(s: String): Unit
          def setKeyPassword(s: String): Unit
          def setTruststore(s: String): Unit
          def setTrustPassword(s: String): Unit
        }]
        val addConnector: java.lang.reflect.Method = server.getClass.getMethod("addConnector", cl.loadClass("org.mortbay.jetty.Connector"))

        ssl.setPort(8443)
        ssl.setMaxIdleTime(30000)
        ssl.setKeystore(info.projectPath + "/src/test/resources/keystore")
        ssl.setPassword("password")
        ssl.setKeyPassword("password")
        ssl.setTruststore(info.projectPath + "/src/test/resources/keystore")
        ssl.setTrustPassword("password")
        addConnector.invoke(server, ssl)
      })
  }
※上記はjetty6の場合で、jetty7の場合はパッケージ・クラス名がちょっと違います。

これで、jetty-runで8080でhttp、8443でhttpsが起動します。