読者です 読者をやめる 読者になる 読者になる

Code for final

ふぁいなる向けのコード置き場です。すでにコードじゃないこともいっぱい。

Rubyのhttps通信で"certificate verify failed (OpenSSL::SSL::SSLError)"というエラーが出たが、証明書を設定するのが面倒でとりあえず動かしたいとき。

Ruby

Rubyで'net/https'を使ってHTTPS通信を行ったとき、以下のエラーがでました。

C:/Ruby23-x64/lib/ruby/2.3.0/net/http.rb:933:in `connect_nonblock': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError)

どうやらSSLの検証に引っかかっているみたいです。

とりあえず動かしたい!ってときは以下のようにverify_modeの指定を追加して検証しないというように設定すればOKです。

        https = Net::HTTP.new('xxx.xxx.xxx',443)
        https.use_ssl = true

        # これを追加
        https.verify_mode = OpenSSL::SSL::VERIFY_NONE

        https.start{
        
        }

以下のマニュアルにはデフォルトはVERIFY_NONEって書いてありますけど、追加しないと動きませんでした。

instance method Net::HTTP#verify_mode= (Ruby 2.3.0)

正しく対処するには証明書をダウンロードして明示的に指定する必要があるらしいですが、とりあえず動かしたいときはこれだけでOKですね。

管理したいソースに対応した.gitignoreを自動で生成してくれるサービス。

Good WebService

gitになれるとなんでもgitで管理したくなりますが、面倒なのがgitの除外設定です。

gitignore.ioは管理するソースに対応した.gitignoreのテンプレートを出力してくれるサービスです。

VisualStudioやEclipseってキーワードをいれるだけで生成されます。

便利なことに複合することもできます。

こりゃ便利!

www.gitignore.io

f:id:finalstream:20160827195843p:plain

C#で動的にコンテキストメニューを作成したとき、初回だけ表示されないときはOpeningイベントでe.Cancelにfalseを設定するべし。

C#

ExplorerWindowsCleanerにデスクトップをダブルクリックでコンテキストメニュー(右クリックメニュー)を表示するように 実装したんですけど、なぜか初回のダブルクリックだけ表示されませんでした。

2回目以降のダブルクリックで表示されるので、しばらくそのまま使っていたのですが、なんか気になったので調べてみることに。

デバッグしてみるとContextMenuStrip.Show()は実行されているみたいです。

ぐぐってみるとドンピシャな以下のエントリーを発見。

stackoverflow.com

このエントリーにとOpeningイベントでe.Cancelにfalseを設定すればいいよ的なことがかいてあったのでそのとおりにやってみる。

            _contextMenuShortcuts = new ContextMenuStrip();
            _contextMenuShortcuts.Opening += (sender, e) =>
            {
                _contextMenuShortcuts.Items.Clear();
                _contextMenuShortcuts.Items.Add("Explorer", null, (o, eventArgs) => _explorerCleaner.OpenExplorer(""));
                _contextMenuShortcuts.Items.Add(new ToolStripSeparator());

                var closedExplorers = _explorerCleaner.ClosedExplorers.OrderByDescending(x => x.IsFavorited)
                    .ThenByDescending(x => x.LastUpdateDateTime).Take(10);

                foreach (var closedExplorer in closedExplorers)
                {
                    var item = new ToolStripMenuItem(closedExplorer.LocationPath);
                    item.Image = closedExplorer.IsFavorited ? Resources.favorite : null;
                    item.Click += (o, eventArgs) => _explorerCleaner.OpenExplorer(closedExplorer);
                    _contextMenuShortcuts.Items.Add(item);
                }

                if (_shortcuts.Length > 0)
                {
                    _contextMenuShortcuts.Items.Add(new ToolStripSeparator());
                    foreach (var shortcutItem in _shortcuts)
                    {
                        _contextMenuShortcuts.Items.Add(shortcutItem.Name, null,
                            (o, eventArgs) => shortcutItem.Exec());
                    }
                }

                // これを追加
                e.Cancel = false;
            };

e.Cancel = falseを追加するだけで、すると初回から表示されました。

つまり、コンテキストメニューをプログラム上で生成して、中のメニューをOpeningイベントでのみ設定している場合は、最初はメニューが空なのでコンテキストメニューを表示しないようにe.Cancelがtrueで呼ばれるというわけですな。

MSDNの以下のエントリーにも書いてありますね。わかりにくいですけど。

How to: Add ToolStrip Items Dynamically

理由がわかってスッキリスッキリ。

C#でWin32 API(グローバルフック等)を使用してデバッグすると「指定されたモジュールが見つかりません」と表示されたとき。

C#

ExplorerWindowCleanerにグローバルフックを実装しようとしてコードを書いてデバッグで起動すると

以下のエラーが…

System.ComponentModel.Win32Exception (0x80004005): 指定されたモジュールが見つかりません。

モジュールが見つからない???

Windows10では対応していないのかーと思い、いろいろググッて調べてみるけどそんな情報はどこにもない。

試しにビルドで生成されたexeをそのまま起動すると普通に動いた。

調べて見ると以下の設定にチェックが入っていると失敗するみたいなので、Visual Studio ホスティング プロセスを有効にする」チェックをはずすと普通に動いた。
それにしてもわかりにくいメッセージが出るんだなー。

f:id:finalstream:20160807184155p:plain

ちなみにVisual Studio ホスティング プロセスを無効にすることのデメリットは以下の3つらしいです。

  • .NET Framework アプリケーションのデバッグが始まるまでの時間が長くなる。
  • デザイン時の式評価が使用できなくなる。
  • 部分信頼デバッグが使用できなくなる。

うん、よくわからない。下の2つが。
けどそんなに問題なさそうな気がする。

詳細はMSDN
https://msdn.microsoft.com/ja-jp/library/ms185330.aspx

intra-martのeBuilderのモジュールプロジェクトで各フォルダに格納するものとデプロイ先まとめ。

intra-mart

intra-martのaccelからeBuilderも大きく変わりました。
モジュールという概念が導入されたことにより、モジュールプロジェクトができました。

アプリを開発するときはeBuilderでモジュールプロジェクトを作成するところから始めます。

モジュールプロジェクトを作成するとデフォルトでフォルダがいくつもあって最初はどういうものかぜんぜんわからなかったので今回は、accel初めての方向けに簡単にまとめます。

まず、モジュールプロジェクトを作成すると以下のようなフォルダ構成になっていると思います。

f:id:finalstream:20160505101243p:plain

そしてそのモジュールプロジェクトのデプロイ先ですが、デフォルトではresinのフォルダにあるwebappsにあるimartになります。

以下のまとめでそれぞれのフォルダのデプロイ先を記述していますが、上記のデプロイ先からの相対パスと思ってください。

そしてスクリプト開発ではsrc/mainの下のフォルダをメインで使うことになると思います。

まず、念頭においておくべきことはプロジェクト内フォルダに格納したものは、ビルド時にデプロイ先にコピーされる。ということです。

アプリ開発で、ソースを修正したのに反映されないみたいなことがあった場合は、デプロイ先のファイルが更新されているか確認することが重要です。
たまーにですが、eBuilderでビルドしてもデプロイ先にコピーされないことがありました。その場合はeBuilderを再起動しましょう。

あとどういう形式のファイルを格納するのかわからない場合はデプロイ先に製品のファイルが入っているのでそれを参考にするといいです。ドキュメントも読んだほうがいいです。

では以下にまとめます。

プロジェクト内フォルダ デプロイ先 格納するもの 備考
src/java
src/generated
src/resources
WEB-INF/libにあるjar 新規開発したアプリのjavaソース javaソースはビルドするとjarにまとめられます
実体はsrc/mainの同名フォルダに格納されます
src/main/conf WEB-INF/conf ログ設定、ルーティング設定、メッセージなどの設定ファイル デフォルトでlog, message, routing-jssp-configフォルダがあります
src/main/jssp WEB-INF/jssp スクリプト開発のソース(htmlとjs) jssp/srcに新規開発したものを格納します
製品カスタマイズする際はsrc/main/jsspの下にplatformとかproductのフォルダを作成してカスタマイズするソースと同じ階層構造にカスタマイズしたソースを配置します
カスタマイズする元となる製品ソースはデプロイ先のWEB-INF/jssp/platfrom、WEB-INF/jssp/productから探します
src/main/plugin WEB-INF/plugin プラグイン設定のxml プラグイン開発した場合のみ使います
src/main/public / クライアントサイドのjavascriptcss、imgとか WEBサーバに配置するような静的コンテンツを配置します
クライアントサイドの製品カスタマイズする際はここに格納するとデプロイ先で上書きされます
src/main/schema WEB-INF/schema XMLスキーマのxsdファイル 使ったことがないので詳しくはわかりません
src/main/storage ストレージ(デフォルトはc:\tmp\storage) テナント環境セットアップ時にストレージ配置したいファイル src/main/storage/systemとsrc/main/storage/publicがあるが、アプリではpublicを使う(PublicStorageのAPIで操作可能)
ここに置いたものはテナント環境セットアップ時のみストレージにコピーされるので注意(ビルドではコピーされない)
src/main/webapp WEB-INF javaの製品カスタマイズソースとか WEB-INFに格納されたファイルを上書きしたいときに使います
javaの製品ソースをカスタマイズする際はsrc/main/webapp/classesの下にjavaファイルを配置します(resin起動時にコンパイルされてclassファイルになります)

詳細はアプリケーション開発ガイドに詳しく書いてあるので、読んでみてください。

目次 — アプリケーション開発ガイド   第12版 2015-12-01   intra-mart e Builder for Accel Platform

intra-mart(accel)でModule.alertの代わりとなるっぽい汎用的に使えるエラー画面を出す。

intra-mart

intra-martを昔からやっている人はわかると思いますが、製品標準でエラー画面が用意されています。

そうです、Module.alertオブジェクトです。
エラー画面というか警告画面っぽいですけど。

以下のようにサーバサイドでメッセージID、詳細メッセージを渡すだけで戻るボタン付きのエラー画面が出せます。

Module.alert.back(messageId, detail);

intra-mart Accel Platform SSJS API Documentation

intra-martで作成された業務アプリでシステムエラーが出た際はこれに頼っているケースがほとんどではないかと思います。

そんなModule.alertですが、accelから非推奨になりました。
しかも、代替えメソッドはありません。と書いてあります。

なぜなくなった? why?

まぁエラー画面くらい自分で作りなさいってことかーと理解して
UIデザインガイドラインを見てたらなんと代替っぽいのがありました。

6.5.2. 汎用メッセージ画面 — UIデザインガイドライン(PC版)   第5版 2015-04-01   intra-mart Accel Platform

なぜにUIデザインガイドラインに?ということは置いといて、渡せるものも増えていろいろパワーアップしているみたいです。

Transferオブジェクト intra-mart Accel Platform SSJS API Documentation

以下のようなコードをサーバサイドで書けばOKです。

      Transfer.toErrorPage({
        title: 'タイトル',
        message: 'メッセージ',
        detail: ['詳細メッセージ1', '詳細メッセージ2'],
        returnUrl: '/login', // 戻り先 URL
        returnUrlLabel: 'ログイン画面へ戻る',
        parameter: {
          key: 'value',
          list: ['1','2','3']
        }
      });

↓上記のコードで出るエラー画面 f:id:finalstream:20160503200108p:plain

これってModule.alertの代替ちゃうん?って思いましたが、accelで汎用的なエラー画面を表示するときはTransferオブジェクトを使いましょう。

そもそもaccelの開発ではajaxをメインでやると思うので、エラーメッセージはクライアントサイドでimuiShowErrorMessageを使って出すことが多く、あまり使う機会はないかもしれませんが覚えておいて損はないと思います。

intra-mart Accel Platform Client Side JavaScript API - imuiShowErrorMessage

intra-martで作成したアプリ(スクリプト開発)のログを簡単に出力する方法。

intra-mart

ログ絡みでもう一個だけ。

intra-martで作成したアプリ(スクリプト開発)でログを簡単に出力するやり方です。
スクリプト開発プログラミングガイドの記載内容ではちょっとだけ理解に時間がかかったのでまとめときます。

1. ログ設定を作成する。

アプリ用のログ設定を作成します。
loggerのnameはソースを配置するフォルダ名と同じにする必要があるので注意してください。
appenderとか指定していないのでログは標準出力(コンソール)に出ます。
リリース時はレベルをoffにすれば出なくなります。
内容は以下のように書きます。作成後は再起動してください。

WEB-INF/conf/log/im_logger_appname.xml

<included>

  <!-- jsspのappnameフォルダ配下のソースで有効になるロガー設定 -->
  <logger name="appname">
    <level value="debug" />
  </logger>

</included>

 

2. コードを書く。

あとはログを出力するコードを書くだけです。
以下の例では結果のオブジェクト(result)をjson形式でデバッグログとして出力しています。
コードはログ設定で指定したnameのフォルダ名(appname)配下のソースに記述する必要があります。

f:id:finalstream:20160502232547p:plain

sandbox.js

     // ロガーを生成
     var logger = Logger.getLogger();

     // なんか処理した結果を想定
     var result =  { error: false, count: 10 };

     // デバッグが有効の場合、resultをjson形式でログに出力
     if(logger.isDebugEnabled()) logger.debug('init() result: {}', ImJson.toJSONString(result));

上記のたった2つを行うだけで以下のようなログがコンソールに出力できます。
Loggerにobjectをそのまま渡しても[object object]と出るだけですので、ImJson.toJSONString()でstringにしています。

[DEBUG] a.sandbox - [] init() result: {"error" : false, "count" : 10}

ロガー名は"a.sandbox"となっていますが、デフォルトではコンソールに出力されるロガー名は指定した長さになるように省略されます。
省略しない場合は"appname.sandbox"で、ファイルに出力した場合は省略されずに出ます。

ロガー名はjavaだと完全修飾クラス名(FQCN)ですが、スクリプト開発だとsrcフォルダ配下のファイルパスを.で区切ったものになるみたいです。

※ちなみに説明で使用しているappnameは開発するアプリの名前に変更してください。