クリアフィルター
記事
Saori Murata · 2024年9月30日
開発者の皆さん、こんにちは!
InterSystems IRIS(以下、IRIS)を使用したアプリケーション開発において、皆さんは環境設定をどうされていますか?
私は最近になって、「インストールマニフェスト」という機能があることを知りました。
これは、管理ポータルでポチポチしていた作業をコード化・自動化できる強力なツールです!
最初こそとっつきづらかったものの良いところがたくさんあるなと思ったので、簡単にではありますが皆さんにその良さと始め方をご紹介したいと思います。
なお、私が使用しているIRISバージョンは以下です。
>2022.1
バージョンが異なる場合、違う書き方になっているもの等が存在する場合がありますので、
公式ドキュメント等を参照し適宜読み替えていただければと思います。
# 目次
1. はじめに
2. インストールマニフェストとは
3. インストールマニフェストのメリット・デメリット
4. インストールマニフェストの始め方と基本構造
1. マニフェストの作成
2. マニフェストの編集
3. マニフェストの実行
5. インストールマニフェストでできること
1. 変数の設定
2. ネームスペースとデータベースの設定
3. データのインポートとマッピング
4. セキュリティ設定
5. InterOperability 機能の設定
6. インストールマニフェスト以外で行う環境設定
1. ObjectScriptによる実装
2. Pythonによる実装
7. まとめ
# 1. はじめに
IRISを使用するにあたって、管理ポータルでの環境設定は切っても切れない作業だと思います。
IRIS のインストールマニフェストを使用することで、ネームスペース、データベース、セキュリティ設定、InterOperabilityの有効化、
さらにはカスタムコードの実行まで、一連のプロセスを自動化することができます。
本記事では、実際のマニフェストファイルを例に挙げながら、IRIS の環境設定自動化の方法について解説します。
なお、本記事で解説しているサンプルコードの全文と、付随するフォルダ・ファイルについては、[Github](https://github.com/SaoriMurata/IRIS-Manifest-Sample/tree/main)にて公開しています。
# 2. インストールマニフェストとは
IRIS のインストールマニフェストとは、`%Installer`というツールのことを指します。
インストールマニフェスト定義を記述するだけで、
IRIS環境設定を変更するために必要なコードを自動生成することができます。
他人に共有する際は、定義したインストールマニフェストを配布するだけで済みます。
インストールマニフェストは XML 形式で記述されます。
主要な要素として ``、``、``、`` などがあります。
なお、公式ドキュメントは以下です。
>[インストール・マニフェストの作成および使用](https://docs.intersystems.com/iris20211/csp/docbookj/DocBook.UI.Page.cls?KEY=GCI_manifest)
# 3.インストールマニフェストのメリット・デメリット
私が使ってみて感じた、インストールマニフェストのメリット・デメリットについてお伝えします。
全ての場合でインストールマニフェストが優れているとは言えないと思いますので、下記を参考に使用したほうが良いかどうか判断してもらえたらと思います。
- メリット
- IRIS環境構築(管理ポータルで手動で実行していた作業)の**自動化ができる**
- 環境構築内容を**コードとして管理できる**
- **共通の環境を誰でも簡単に、素早く作れるようになる**
- 事前に内容を定義しておけるので、管理ポータルで操作してうっかり**設定ミスや設定忘れをしてしまうといったことがなくなる**
- デメリット
- 環境構築経験が豊富でない人にとっては、公式ドキュメントを読みながらでもコードが示す**内容の把握が難解なところがある**
- マニフェストの記法を理解した人でないと、**コードのメンテナンスを実施できない**
- 定義の作成、定義の配布、実行方法の共有など、事前準備に手間がかかるため、少人数の環境が対象だったり、設定項目が少なかったりすると**手間のほうが大きくなる可能性がある**
# 4. インストールマニフェストの始め方と基本構造
## 4-1. マニフェストの作成
インストールマニフェストは、簡単に作成することができます。
例えばあなたがスタジオを使っている場合、下記の手順でテンプレートを作成できます。
> ファイル > 新規作成 > 一般 > %Installer マニフェスト > OK
こうして作成されるマニフェストは、以下のようになっています。
```xml
Include %occInclude
/// %Installer Manifest MyApp.MyInstaller
Class MyApp.MyInstaller
{
/// マニフェスト定義.
XData MyManifest [ XMLNamespace = INSTALLER ]
{
}
/// これは XGL により生成されたメソッド・ジェネレーターです。.
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]
{
#; XGL ドキュメントでこのメソッドのコードを生成する.
Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyManifest")
}
}
```
## 4-2. マニフェストの編集
なにやら見覚えのないコードがたくさん生成されますが、安心してください。
そのうち、私たちが編集すればよいのは基本的に下記の部分のみです。
```xml
```
### ■マニフェストの基本構造
詳細については後ほど解説しますが、ここでは基本的な構造について紹介していきます。
- ``:**すべてのタグのルートタグである必要がある。** 他のすべてのタグを含む。
- ``:**ネームスペースを定義する。** 【親タグ:``】
- ``:``内で構成タグの親タグとして記述する必要がある。【親タグ:``】
- ``:**データベースを定義する。** 【親タグ:``】
ここで覚えるべきは、``タグは唯一無二ですべてのルートタグとなること、
その中身となるそれぞれのタグにも親子関係があるためそれを守らなければならないこと、の2点です。
これら以外の記述は、インストールマニフェストの作成や実行に必要なコードです。
詳細の説明については、下記のページにあるので任せたいと思います。
> [%InstallerでInterSystems Cachéにアプリケーションをデプロイする](https://jp.community.intersystems.com/post/installer%E3%81%A7intersystems-cach%C3%A9%E3%81%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%99%E3%82%8B)
## 4-3. マニフェストの実行
このマニフェストを実行したいときは、ターミナルで以下のコマンドを実行してください。
※マニフェストを実行する時は、%SYSネームスペースで実行することを推奨します。(それ以外のネームスペースでも動作はします)
```
USER>zn "%SYS"
%SYS>do ##class(MyApp.MyInstaller).setup()
```
そうすると、マニフェストが環境設定のためのコードを生成し、そのコードが実際にIRISの環境設定を変更していきます。
# 5. インストールマニフェストでできること
それではさっそく、インストールマニフェストで実際にできることについてみていきましょう。
私が触ったことのある機能を中心に紹介していますが、前述の公式ドキュメントにはそれ以外の設定もできるXMLタグが多数紹介されていますので、参照してみてください。
## 5-1. 変数の設定
マニフェストでは、変数を設定することができます。
変数設定ができるタグには2種類あります。
- ``:変数値がまだ設定されていない場合のみ、変数値を設定します。(すでに値が設定されている場合、無効になる)【親タグ:``】
- ``:マニフェストで使用できる変数を定義および設定します。【親タグ:``】
```xml
// 事前に変数 var1 が設定されているので、var1 は aaa のまま
// 事前に変数 var2 は設定されていないので、var2 は ccc になる
```
## 5-2. ネームスペースとデータベースの設定
マニフェストを使用して、ネームスペースとそれに関連するデータベースを簡単に作成できます。
関連するタグは3種類です。
- ``:ネームスペースを定義する。【親タグ:``】
- Name:ネームスペースの名前
- Create:新しいネームスペースを作成するかどうか(yes/no/overwrite) ※デフォルト:yes
- Code:コード用データベースの指定
- Data:データ用データベースの指定
- Ensemble:InterOperabilityを使用するネームスペースかどうかの指定
- ``:`` 内で構成タグの親タグとして記述する必要がある。【親タグ:``】
- ``:データベースを定義する。【親タグ:``】
- Name:データベース名
- Dir:データベース・ディレクトリ
- Create:新しいデータベースを作成するかどうか
- InitialSize:データベースの初期サイズ(MB)
- Resource:データベースへのアクセスを制御するリソース
- PublicPermissions:リソースに割り当てられる許可の値(新規作成リソースのみ適用)(R/W/RW)
```xml
```
### ■結果(管理ポータル画面)
(ネームスペース)
(データベース)
## 5-3. データのインポートとマッピング
マニフェストを使用して、特定のネームスペースに既存のデータやコードをインポートすることもできます。
関連するタグは1種類です。(既出除く)
- ``:ファイルをインポートする。(%SYSTEM.OBJ.ImportDir または %SYSTEM.OBJ.Load を使用する)【親タグ:``】
- File:インポートするファイルまたはフォルダ
- Flags:コンパイル・フラグ(参考:[フラグおよび修飾子](https://docs.intersystems.com/ens20181j/csp/docbook/Doc.View.cls?KEY=RCOS_vsystem#RCOS_vsystem_flags_qualifiers))
- Recurse:再帰的にインポートするかどうかを指定 ※デフォルト:0
- IgnoreErrors:エラー時に続行するかどうかを指定 ※デフォルト:0
```xml
```
### ■結果(管理ポータル画面)
マニフェストを使用して、グローバルやクラスをマッピングすることもできます。
関連するタグは3種類です。(既出除く)
- ``:グローバルを現在のネームスペースにマッピングする。【親タグ:``】
- Global:グローバル名
- From:グローバルのソース・ネームスペース
- ``:パッケージを現在のネームスペースにマッピングする。【親タグ:``】
- Package:マップするパッケージ
- From:マッピングに使用するソース・データベース
- ``:ルーチンを現在のネームスペースにマッピングする。【親タグ:``】
- Name :ルーチン
- Type :ルーチン・タイプ
- From:ルーチンのソース・データベース
```xml
```
### ■結果(管理ポータル画面)
## 5-4. セキュリティ設定
マニフェストを使用して、ロールやユーザアカウントを複数作成することができます。
関連するタグは2種類です。
- ``:ロールを定義する。【親タグ:``】
- Name:ロール名
- Description:ロールの説明(カンマ不可)
- Resources:ロールで保持されているリソースと特権。
- RolesGranted:付与されるロール
- ``:ユーザを定義する。【親タグ:``】
- Username:ユーザ名
- PasswordVar:ユーザ・パスワードが含まれる変数の名前(変数名を渡す必要があることに注意)
- Fullname:ユーザのフルネーム
- Roles:ユーザを割り当てるロールのリスト
- Namespace:ユーザの実行開始ネームスペース
- Enabled:ユーザが有効かどうか
- Comment:オプションコメント
- ChangePassword:次回ログイン時にユーザにパスワードの変更を要求するかどうか
- ExpirationDate:それ以降のユーザ・ログインが無効になる日付
```xml
```
### ■結果(管理ポータル画面)
(ロール)
(ユーザ)
### ■クラスメソッドの実行(Invoke)
また、管理ポータルのセキュリティ設定をまるっと読み込むこともできます。
これにより、管理ポータルやターミナル等のログインの有効化や、詳細のセキュリティ設定までを一括で行うことができます。
ロールやユーザアカウントについても、この読み込みにより一括で作成することができます。
関連するタグは2種類です。(既出除く)
- ``:クラス・メソッドを呼び出して、実行結果を変数の値として返す。【親タグ:``】
- Class:クラス名
- Method:メソッド名
- CheckStatus:返されたステータスをチェックするかどうか
- Return:結果の書き込み先の変数の名前
- ``:`` または `` から呼び出されるメソッドに引数を渡す。【親タグ:``, ``】
- Value:引数の値
```xml
```
これらのタグは、**セキュリティ設定のインポート以外にも様々な用途に使用することができます**。
例えば、タスクスケジュール全体のインポートをセキュリティと同じように行ったり、自作のクラスの処理を実行したり、既存のシステムクラスの処理を実行したりなどです。
※管理ポータルのログインの有効化設定については、2024.3以降のバージョンであればマニフェストのタグにて変更することができます。
(ターミナルのログイン有効化については、現在は``を用いる方法か、後述の別途マニフェスト以外のコードを書く方法で実現するしかありません)
具体的には、下記のタグで実現できます。
- ``:クラス内で定義されている 1 つ以上の Web アプリケーションを定義する。【親タグ:``】
- AuthenticationMethods:有効な認証方法(例:32=password、64=unauthenticated)
- CSPEnabled:CSP が有効かどうか ※デフォルト:1
- DefaultTimeout:セッション・タイムアウト
- Description:説明
- Directory:CSP ファイルへのパス
- Url:Webアプリケーションの名前
- :
※セキュリティ設定のインポートの事前準備として、管理ポータルのセキュリティ設定(上述の「SecurityExport.xml」にあたるもの)をXMLとしてエクスポートしておく必要があります。
エクスポートは、次のように実施します。
ターミナルで^SECURITY ユーティリティを起動し、`12) System parameter setup` > `5) Export All Security settings` を選択します。
そうすると、`C:\InterSystems\[IRISインスタンス名]\mgr\SecurityExport.xml` ができているはずです。
(IRISを入れている場所によっては出力場所は異なります)
> [★4.セキュリティ情報(ユーザ・サービスなど)のインポート](https://jp.community.intersystems.com/post/%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%83%9E%E3%83%8B%E3%83%95%E3%82%A7%E3%82%B9%E3%83%88%E3%81%AEtips%E9%9B%86#4)
> [InterSystems 製品の設定内容をインポート/エクスポートする方法](https://jp.community.intersystems.com/post/intersystems-%E8%A3%BD%E5%93%81%E3%81%AE%E8%A8%AD%E5%AE%9A%E5%86%85%E5%AE%B9%E3%82%92%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88%EF%BC%8F%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95) > セキュリティについて
```
%SYS>Do ^SECURITY
:
Option? 12 // System parameter setup
:
Option? 5 // Export All Security settings
Export ALL security records? Yes => Yes
Export to file name SecurityExport.xml =>
Parameters? "WNS" =>
Confirm export of selected security records to SecurityExport.xml? No => Yes
```
### ■結果(管理ポータル画面)
(デフォルトでは管理ポータルのログイン時にパスワード認証はないが、それをマニフェストで有効化した例)
## 5-5. InterOperability 機能の設定
InterOperability機能を使用する場合、専用のネームスペースを作成することができます。
また、プロダクションを自動的に設定することもできます。
関連するタグは2種類です。``も改めて紹介します。
- ``:ネームスペースを定義する。【親タグ:``】
- Name:ネームスペースの名前
- Create:新しいネームスペースを作成するかどうか(yes/no/overwrite) ※デフォルト:yes
- Code:コード用データベースの指定
- Data:データ用データベースの指定
- Ensemble:**InterOperabilityを使用するネームスペースかどうかの指定**
- ``:プロダクションを定義する。【親タグ:``】
- Name:プロダクション名
- AutoStart:プロダクションを自動的に起動するかどうか ※デフォルト:0
```xml
```
### ■結果(管理ポータル画面)
# 6. インストールマニフェスト以外で行う環境設定
マニフェストを作成していると、管理ポータルでは設定できるけどマニフェストではどうやるのだろう?という設定に度々出会います。
公式ドキュメントを見るなどしてマニフェストでの実現方法がわかる場合もありますが、
中にはマニフェストでは実現方法がないもの、後続のバージョンでは修正されたが今使っているバージョンではバグが残っており実現できないもの、
等がある場合があります。
その場合、あきらめて管理ポータルで設定するというのも手ですが、
別途コード化してマニフェストの処理と一緒に実施してしまうのもありです。
実際に、いくつかの設定をマニフェスト以外のコードで実現し、それをマニフェストと一緒に実行するコードの簡単な例をご紹介します。
## 6-1. ObjectScriptによる実装
下記のコードでは、マニフェストの生成・実行処理であるsetupメソッド(前述のスタジオでの新規作成にて自動作成されるメソッド)を、
自作のsetupExecuteというメソッドでラップしています。
その上で、ロケールの変更や不要タスクの一時停止といった処理をコードで記述し、実行します。
```
/// マニフェスト生成・実行処理
/// SAMPLES>
/// Do ##class(MyApp.MyInstaller).setup()
///
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]
{
#; XGL ドキュメントでこのメソッドのコードを生成する.
Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyManifest")
}
/// セットアップ開始処理
/// return %Status
/// SAMPLES>
/// Do ##class(MyApp.MyInstaller).setupExecute()
///
ClassMethod setupExecute(ByRef pVars) As %Status
{
Set tSC = 0
New $NAMESPACE
Set $NAMESPACE = "%SYS"
#; すでにネームスペースがあるときはManifestの処理はスキップ
If ('##class(%SYS.Namespace).Exists("TESTNMSP")) {
Set tSC = ..setup(.pVars)
}
#; 日本語ロケールへ変更
Do ##class(Config.NLS.Locales).Install("jpuw")
#; 不要なタスクを停止
Do ..SuspendTask()
Return tSC
}
/// タスク停止
/// 不要なタスクスケジュールを停止する。
/// SAMPLES>
/// Do ##class(MyApp.MyInstaller).SuspendTask()
///
ClassMethod SuspendTask()
{
Set targetId = -1
Set query = 0
Set query($INCREMENT(query)) = "SELECT %ID,Name FROM %SYS.Task"
Set tStatement = ##class(%SQL.Statement).%New()
Do tStatement.%Prepare(.query)
Set result = tStatement.%Execute()
While (result.%Next()) {
If (result.%GetData(2) = "機能トラッカー") {
Set targetId = result.%GetData(1)
Quit
}
}
If (targetId '= -1) {
#; 機能トラッカーを一時停止
Do ##class("%SYS.TaskSuper").Suspend(targetId)
}
}
```
これを実行する時は、setupメソッドではなくsetupExecuteメソッドを、ターミナルから実行します。
%SYSネームスペースから実行してください。
```
USER>ZN "%SYS"
%SYS>Do ##class(MyApp.MyInstaller).setupExecute()
```
### ■結果(管理ポータル画面)
(機能トラッカーを一時停止した結果)
## 6-2. Pythonによる実装
本題からは逸れてしまいますが、「InterSystems Embedded Python」について私は今まで触ったことがなかったため、この機会にチャレンジしてみました。
簡単にですが、その結果と所感について述べたいと思います。
6-1の内容を、Embedded Pythonを用いて書き換えたコードは以下です。
※setupメソッドについては「objectgeneratorメソッド」という特別なメソッドのため、ObjectScriptのみでしか動作しません。そのため、Pythonへの書き換えはできないようでした。
```
/// マニフェスト生成・実行処理
/// SAMPLES>
/// Do ##class(MyApp.MyInstaller).setup()
///
ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]
{
#; XGL ドキュメントでこのメソッドのコードを生成する.
Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "MyManifest")
}
/// セットアップ開始処理
/// return %Status
/// SAMPLES>
/// Do ##class(MyApp.MyInstaller).setupExecute()
///
ClassMethod setupExecute(pVars As %SYS.Python = "") As %Status [ Language = python ]
{
import iris
tSC = 0
# すでにネームスペースがあるときはManifestの処理はスキップ
if not iris.cls('%SYS.Namespace').Exists('TESTNMSP') == 1:
tSC = iris.cls(__name__).setup(pVars)
# 日本語ロケールへ変更
iris.cls('Config.NLS.Locales').Install('jpuw')
# 不要なタスクを停止
iris.cls(__name__).SuspendTask()
return tSC
}
/// タスク停止
/// 不要なタスクスケジュールを停止する。
/// SAMPLES>
/// Do ##class(MyApp.MyInstaller).SuspendTask()
///
ClassMethod SuspendTask() [ Language = python ]
{
import iris
targetId = -1
df = iris.sql.exec('SELECT %ID,Name FROM %SYS.Task').dataframe()
for i in range(len(df)):
if df.iloc[i, 1] == '機能トラッカー':
targetId = df.iloc[i, 0]
break
if not targetId == -1:
# 機能トラッカーを一時停止
iris.cls('%SYS.TaskSuper').Suspend(int(targetId))
}
```
※SuspendTaskメソッドの実行に当たっては、事前にpandasライブラリのインストールが必要です。
未インストールの場合、下記のコマンドを実行してインストールを実行してください。
(IRISを入れている場所によっては対象のパスは異なります)
```
> cd C:\InterSystems\[IRISインスタンス名]\bin
> irispip install --target ..\mgr\python pandas
```
Embededd Pythonを少しだけ使用してみた所感としては、
純粋にPythonを書くところは知っている記法をそのまま書けるので苦なく書けましたが、
IRISとの連携部分(IRISのクラスを利用するなどIRIS独自の機能を利用したいとき)は都度書き方を調べる必要があったので少し大変でした。
一度書き方を覚えてしまえばより多くのコードを書く時でも問題なさそうですが、慣れが必要だと思います。
ObjectScriptの記法に慣れていると、ObjectScriptで当たり前にできることがPythonでは実装が難しい、直感的に書けない場合もあるようなので、注意が必要です。
しかし、それを踏まえてもコードをPythonで書けるのは良いと思いました!
Pythonの記法のメリットとしてObjectScriptよりもシンプルに記載できる箇所も多いですし、
前述のPythonでは実装が難しい部分についても、バージョンがあがっていくことで機能は徐々に追加されていくと思いますので、これからに期待ができます。
なにより、ObjectScriptの経験がない人に対しても共通の言語を持てるというのはとても素晴らしいことだと思います。
これを実行する時は、ObjectScriptのときと同じで問題ありません。
%SYSネームスペースから実行してください。
※そうでないと、「Config.NLS.Locales」の実行時にエラーとなります(%SYSにあるパッケージのため)
```
USER>ZN "%SYS"
%SYS>Do ##class(MyApp.MyInstaller).setupExecute()
```
# 7. まとめ
IRIS のインストールマニフェストを使用することで、環境設定の自動化が可能になり、共通の環境を素早く構築できます。
これにより、開発チームの生産性が向上し、人為的なミスも減らすことができそうです。
本記事で興味を持っていただいた方は、ぜひインストールマニフェストを使ってみてください!
以上、ここまでお読みいただきありがとうございました。
記事
Hiroshi Sato · 2020年10月19日
これはInterSystems FAQ サイトの記事です。
2つのステップにて作業します。
クラス定義の移行
クラス定義を別システムへ移行するため、XML形式またはUDL形式(拡張子.cls)のファイルにエクスポートします。
スタジオでのエクスポート手順は以下の通りです。
[ツール] > [エクスポート]
> [追加]ボタンで移行したいクラスを複数選択
> [ローカルファイルにエクスポート]にチェック
> ファイルの種類がXMLであることを確認し、ファイル名を入力し、[OK]
この後、別システム上のスタジオで、エクスポートしたXML、UDLファイルをインポートします。
この手順で、クラス定義は移行できます。
スタジオでのインポート手順は以下の通りです。
[ツール] > [ローカルからインポート]
> 上記手順で出力したXML、UDLファイルを指定します。
データの移行
次に実際のデータを移行します。オブジェクトデータは既定では、以下の命名規則のグローバル変数内に格納されています。データ :^クラス名Dインデックス:^クラス名Iストリーム :^クラス名S例)User.testクラスのデータは以下の3つのグローバルに格納されます。^User.testD, ^User.testI, ^User.testS
これらのうち存在するグローバル変数をすべて、システム管理ポータル(Caché5.0以前では、エクスプローラ)から、エクスポートします。
エクスポート手順は以下の通りです。 【バージョン2011.1~】
管理ポータルを利用する場合、以下メニュからエクスポートを行います。
[システムエクスプローラ] > [グローバル] ([グローバル]をダブルクリックか、移動ボタンを押下)
> 左ペインからネームスペースを選択する> [エクスポート]をクリック> エクスポートしたいグローバルをチェックし、出力ファイル名を指定 【バージョン2010.2以前】
システム管理ポータルを利用する場合、以下メニュからエクスポートを行います。
データ管理→グローバル
→ 左ペインからネームスペースを選択する→ 「エクスポート」をクリック→ エクスポートしたいグローバルをチェックし、出力ファイル名を指定
次に上記ファイルを、別システムにインポートします。
インポート手順は以下の通りです。 【バージョン2011.1~】
管理ポータルを利用する場合、以下メニュからインポートします。
システムエクスプローラ→グローバル (「グローバル」をダブルクリックか、移動ボタンを押下)
→ 左ペインからネームスペースを選択する→ インポートをクリック→ エクスポートしたファイルを指定→ インポートを実行 【バージョン2010.2以前】
システム管理ポータルを利用する場合、以下メニュからインポートします。
[データ管理] > [グローバル]> 左ペインからネームスペースを選択する> インポートをクリック> エクスポートしたファイルを指定> インポートを実行
以上で、データの移行が完了します。
お知らせ
Mihoko Iijima · 2024年2月14日
2024年1月の開発者コミュニティリリースニュースをお伝えします。
開発者コミュニティをより素晴らしい場所とするため、以下の機能について更新を行いました。
📌 ニックネーム🆕
📌 Credly バッジ
📌 サブスクリプション
📌 GIFの再生/一時停止
📌 タグの自動付与
それぞれの更新について、以下詳細をご紹介します!
タグの自動付与
投稿を作成するときのタグ入力を支援するためにAIを利用するように変更しました。(ですが、機械は人間ほど進化していないことをお忘れなく・・)
ニックネーム
開発者コミュニティで、姓・名の代わりにニックネームを利用できるようになりました!
使用される場合は、プロフィール設定画面でニックネームを設定してください。名前を隠してニックネームを使うこともできます!プロフィール情報を変更するには、ページ右上に表示されているアイコン(破線□)にカーソルを合わせメニューから「プロフィール設定」をクリックしてください。
変更が反映されるまでに最大24時間を要する場合があることをご留意ください。
Credly バッジ
Credlyバッジの視認性を向上させました。プロフィールのメインページですべてのバッジを確認できるようになりました。
(プロフィールページの「公式認定証とCredlyバッジ」を選択すると参照できます)
上の画像のバッジは、オンラインラーニングのラーニング・パス (例:Building Custom Integrations など)で全てのパスを終了し小テストをクリアすることで入手できるバッジです。
ラーニング・パスはいろいろな種類があります👉 InterSystems Learning Paths
気になる内容からぜひチャレンジしてみてください!
サブスクリプション
サブスクリプションの設定を全面的に改良し、より利用しやすい画面に変更しました。
ニュースレターを購読されている方は、デザインが変わったことにお気づきですね?
まだ購読されてない方は、ぜひこの機会に設定を行ってみてください。(週間、月間、年間のニュースレターの設定が行えます。)
設定を行うには「プロフィール設定」→「サブスクリプション」に進んでください。
GIFの再生と一時停止
この機能は、皆様よりいただいた「アイデアポータル」のアイデアから実装された機能でGIFに再生ボタンが追加されました。
デフォルトではGIFは再生ボタンをクリックするまで一時停止されます。
開発者コミュニティの更新を気に入っていただけると嬉しいです🤗
記事
Megumi Kakechi · 2023年5月30日
これは InterSystems FAQ サイトの記事です。
Apache環境でRESTを動かすための設定方法は以下のとおりです。
1. Webゲートウェイをインストールします
添付(Webゲートウェイインストール手順.pdf)の手順に従い、Webゲートウェイをインストールします。※Webゲートウェイをインストールする前に、Apacheを停止してください。
2. Apache 構成ファイルの設定を行います
/etc/httpd/conf/httpd.conf の末尾に以下を追加します。追加後、Apacheを再起動してください。
<Location /> CSP On SetHandler csp-handler-sa</Location>
※こちらの設定では、Apacheに対するすべてのリクエストをWebゲートウェイに渡す設定になります。 <Location />ではなく、<Location /rest> にすると、/rest のみWebゲートウェイに渡すようになります。 (既に他の目的でApacheを使用している場合、<Location /> の設定にするとそちらが動かなくなりますのでご注意ください)
Apacheの再起動:
# systemctl stop httpd.service // Apache の停止(開始している場合)
# systemctl start httpd.service // Apache の開始
# systemctl status httpd.service // ステータスの確認
3. Webゲートウェイ管理ページに接続できることを確認します
Web Gateway 管理ページ http://localhost/csp/bin/Systems/Module.cxw
4. Webゲートウェイ管理ページで以下の設定を行います
4-1. 接続先IRISサーバの設定
WebGateway の Server Access より、サーバの設定を確認します。※以下はローカルにIRISをインストールしている場合
4-2. アプリケーションアクセスの設定
Web Gateway の Application Access から /rest を追加します。→既存アプリケーションをクリックしてコピーし、アプリケーションパスを /rest に設定 & 4-1.で設定したIRISサーバを指定します。
この構成により、Webゲートウェイは /rest アプリケーションをIRISサーバに転送します。
5. IRISサーバの構成でウェブアプリケーションの設定を行います
IRISサーバの管理ポータル(http://localhost/csp/sys/UtilHome.csp)を開き、
システム構成 > セキュリティ > アプリケーション > ウェブ・アプリケーション
より /rest アプリケーションを追加します。RESTのクラスをディスパッチクラスに指定します(この記事の後方にサンプルコードを載せています)。
この構成により、IRIS は /rest アプリケーションを対象ネームスペースに転送し、対象ディスパッチクラスを呼び出します。
6. Postman や Webブラウザより、GETリクエストを試してみます
以下はローカルにIRISをインストールしている場合です。必要に応じてサーバのIPアドレスに変更してください。 http://localhost/rest/req2 パスワード認証を有効にしている場合、ブラウザからは以下のように実行します。 http://localhost/rest/req2?IRISUserName=<UserName>&IRISPassword=<Password>以下のように、日時が表示されます。
※サンプルコード:
Class User.REST Extends %CSP.REST
{
XData UrlMap
{
<Routes>
<Route Url="/req2" Method="GET" Call="req2"/>
</Routes>
}
ClassMethod req2() As %Status
{
write $ZDT($H)
quit $$$OK
}
}
【ご参考】IISでRESTを動かす場合の設定方法
記事
Tomoko Furuzono · 2023年4月10日
これは、InterSystems FAQサイトの記事です。管理ポータル:システムエクスプローラの使用には、%DevelopmentリソースのUse特権が必要です。システムエクスプローラでの参照のみ利用可能とする権限をユーザに付与したい場合は、%DevelopmentリソースのUse特権(※1)と、該当のデータベースリソース(※2)への参照特権(R)を付与したロールを作成し、これをユーザに与えます。※1.「%Development:U」を付与している場合はターミナルやスタジオも参照のみで使用可能となります。※2.参照したいデータベースに割り当てられているリソースが%DB_DEFAULTリソースになっており、このデータベースのみに参照権限を設定したい場合は、事前に、このデータベース用の独自リソース(%DB_<データベース名>)を作成し、該当データベースに割り当てるようにします。
<図:独自リソースの作成>[管理ポータル]>[システム管理]>[構成]>[システム構成]>[ローカルデータベース]>(該当データベースを選択)
【例】:testAユーザに、TESTデータベースへの参照のみを許可する。1.新規ロール作成
2.ロール編集(リソースへの権限の追加)
3.上記で作成したロールをユーザに付与。以上の設定で、testAユーザは、システムエクスプローラでの該当データベースへの参照のみが可能となります。※実際に対象ユーザ(上記testA)が使用する場合は、管理ポータルアクセス後、参照するデータベースに接続できるネームスペースに切り替えた後、システムエクスプローラでの参照を行ってください。
ロールの追加が完了したら、管理ポータルのユーザ定義一覧から該当ユーザのプロファイルを確認し、希望の条件を満たしているか、確認してください。[管理ポータル]>[システム管理]>[セキュリティ]>[ロール]>ユーザ一覧>[プロファイル](一覧の該当ユーザの右端のリンク)
なお、インストール時の初期セキュリティが「最小」の場合、デフォルトでは管理ポータルへはユーザログイン無しでアクセスできます。ユーザログイン出来るようにするためには、管理ポータル用のWebアプリケーションパスの設定として[許可された認証方法]で「パスワード」のみをチェックして、パスワード認証を有効にする必要があります。詳細は、関連トピック「管理ポータル/スタジオ/ターミナルにパスワード認証を設定するにはどうしたらいいですか?」をご参照ください。さらに、SQLでの参照を行いたい場合には、参照したいテーブルへのSQL権限を付与する必要があります。これについての詳細は、関連トピック「SELECTのみを実行できるユーザ作成方法について」をご確認ください。
記事
Hiroshi Sato · 2025年7月27日
これは InterSystems FAQ サイトの記事です。
ODBCクライアントからのアクセスでエラーが発生した場合、返ってきたエラーメッセージやコンソールログ上の情報だけでは原因がよくわからない場合があります。
そのような場合にODBCドライバのクライアントログを有効にすることで、エラーについての詳細情報を取得することができます。
ODBCログの有効化については以下をご参照ください。
ODBCログの有効化
UNIX系のシステムの場合、上記に記載されている通り、2種類のログが取得できます。
クライアント・ドライバ・ログの取得方法 以下の環境変数でトレースのオンと出力するファイルを指定します。
export IRISODBCTRACE=1
export IRISODBCTRACEFILE=/Users/user1/work/odbcclient.log
ドライバマネージャのログの取得方法 ドライバマネージャのデータソース設定ファイル(ODBC.ini)に以下の様にトレースをオンにする設定とログファイルの場所と名前を指定します。
[ODBC Data Sources]
IRIS ODBC User = IRIS iODBC Driver
[IRIS ODBC User]
Driver = /opt/iris/bin/libirisodbc35.so
Description =
Host = localhost
Namespace = USER
UID = _system
Password = SYS
Protocol = TCP
Port = 1972
Trace = on
TraceFile = /Users/user1/work/iodbctrace.log
変更の反映にはODBCクライアントアプリケーションを再起動する必要があります。
クライアントのプロセス毎に個別にログを取得すつこともできます。 クライアントログが正常に取得できている場合、以下の様な内容が書き込まれます。
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Started At: Thu Mar 27 11:02:27 2025
Driver Name: libirisodbc35.so
Unicode Client Version: 2024.2.0.247.0
Compiled at: Jul 16 2024 09:26:07
ODBC Version: 03.51
Locale Setting: ja_JP.UTF-8
ODBC Config file: /Library/ODBC/odbc.ini
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Warning: IRISConnect Failed to load, Error Code: 2; Reason=dlopen(irisconnect.so, 0x0002): tried: 'irisconnect.so' (relative path not allowed in hardened program), '/System/Volumes/Preboot/Cryptexes/OSirisconnect.so' (no such file), '/usr/lib/irisconnect.so' (no such file, not in dyld cache), 'irisconnect.so' (relative path not allowed in hardened program), '/usr/lib/irisconnect.so' (no such file, not in dyld cache)
--> SQLAllocHandle: (03/27/25-11:02:27:224) htype = 1, inhandle = 00000000
--> SQLAllocEnv: (03/27/25-11:02:27:224)
<-- SQLAllocEnv: (03/27/25-11:02:27:224) henv = 0x1301b8000 returning 0
<-- SQLAllocHandle: (03/27/25-11:02:27:224) Returning 0, outhandle = 0x1301b8000
--> SQLSetEnvAttr: (03/27/25-11:02:27:224) henv = 0x1301b8000, Attribute=200, Value=3, StringLength=0
<-- SQLSetEnvAttr: (03/27/25-11:02:27:224) Returning 0
--> SQLAllocHandle: (03/27/25-11:02:27:224) htype = 2, inhandle = 0x1301b8000
--> SQLAllocConnect: (03/27/25-11:02:27:224) henv = 0x1301b8000
<-- SQLAllocConnect: (03/27/25-11:02:27:224) hdbc = 0x1300f0000 returning 0
<-- SQLAllocHandle: (03/27/25-11:02:27:224) Returning 0, outhandle = 0x1300f0000
ドライバマネージャログが正常に取得できている場合、以下の様な内容が書き込まれます。
** iODBC Trace file
** Trace started on Thu Mar 27 11:02:27 2025
** Driver Manager: 03.52.0607.1008
[000000.024585]
soffice 205384840 EXIT SQLDriverConnect with return code 0 (SQL_SUCCESS)
SQLHDBC 0x600002d4cf00
SQLPOINTER 0x0
SQLCHAR * 0x6000017c51a8
SQLSMALLINT 19
SQLCHAR * 0x16d9f9e58
| DSN=IRIS ODBC User;SERVER=localhost;PORT |
| =1972;DATABASE=USER;AUTHENTICATION METHO |
| D=0;UID=_system;PWD=***;STATIC CURSORS=0 |
| ;QUERY TIMEOUT=1 |
SQLSMALLINT 4095
SQLSMALLINT * 0x16d9f9e3e (136)
SQLUSMALLINT 0 (SQL_DRIVER_NOPROMPT)
[000000.024666]
soffice 205384840 ENTER SQLGetInfo
SQLHDBC 0x600002d4cf00
SQLUSMALLINT 25 (SQL_DATA_SOURCE_READ_ONLY)
SQLPOINTER 0x16d9f95d8
SQLSMALLINT 511
SQLSMALLINT * 0x16d9f95d6
ログの内容の解析は専門的な知識が必要となりますので、取得後インターシステムズサポートセンターまでお送りください。
記事
Hiroshi Sato · 2025年9月3日
これは InterSystems FAQ サイトの記事です。
JSON利用の普及に伴いインターシステムズは、JSONに関連する様々な機能強化をIRISに対して行なっています。
その一環として、SQLのJSON_OBJECTのサポートがあります。
この機能に関して現時点より(2025年6月)古いバージョンでは残念ながら制限や不具合が存在しています。
今後も機能強化やバグフィックスを継続していく予定となっているため、この機能の利用を検討および既に利用している方は最新バージョンでのご利用をお勧めします。
ここでは、現時点でわかっている制限事項/不具合についてお知らせします。
VIEW経由でJSON_OBJECTを利用した場合にエラーとなる場合がある 以下のようなクラスとVIEWを定義します。
Class User.test Extends %Persistent
{
Property p1 As %String;
Property p2 As %String;
}
Class User.myview [ ClassType = view, ViewQuery = { select p1 as v10, p1 as v11, p2 as v12 from test } ] { }
この定義に対してデータを登録後、以下のようなSQL文を発行すると、<UNDEFINED>エラーが発生します。
select JSON_OBJECT('x':v10, 'y':v11) from myview
以下のようなエラーメッセージが表示されます。
<UNDEFINED>%0AmBk1+4^%sqlcq.USER.cls47.1
ただしデータが0件の場合はエラーは発生しません。
この問題は、2025.2でも解決していません。
修正時期は未定です。
JSON _OBJECT内にJSON_ARAYAGGを含める場合の問題
サンプルとして提供しているSample.Personの定義をロードします。
サンプルデータの取得方法は以下をご参照ください。サンプルデータの取得データを生成(Populate)した後、以下のようなクエリーを発行します。
SELECT JSON_OBJECT('states': JSON_ARRAYAGG(Home_State) )
FROM Sample.Person WHERE Home_State %STARTSWITH 'D'
以下のような結果が返ってくる場合、それは正しい結果ではありません。
{"states":"[\"DE\",\"DE\",\"DE\",\"DE\",\"DE\"]"}
以下のような結果が正しいものになります。
{"states":["DE","DE","DE","DE","DE"]}
この問題は、2025.1以降のバージョンで修正されています。
SQLの中でCASE文を指定した場合に出力結果が正しくない場合がある。
以下のようなクラス定義とVIEW定義を作成します。
Class JSON.Person Extends %Persistent [ DdlAllowed, ProcedureBlock, SqlRowIdPrivate, SqlTableName = J_PERSON ]
{
Property USERID As %String [ SqlColumnNumber = 2, SqlFieldName = USER_ID ];
Property NAME As %String [ SqlColumnNumber = 3, SqlFieldName = NAME ];
Property SEX As %String [ SqlColumnNumber = 4, SqlFieldName = SEX ];
Index IdxPerson On USERID [ Type = index, Unique ];
}
Class JSON.PersonView [ ClassType = view, CompileAfter = JSON.Person, DdlAllowed, Not ProcedureBlock, SqlTableName = J_PERSON_VIEW, ViewQuery = { SELECT A.USER_ID As USERID, A.NAME As NAME, CASE A.SEX WHEN 'M' THEN '1' ELSE '0' END AS ISMALE FROM J_PERSON A } ] { データを登録します。
データを登録します。
insert into JSON.J_PERSON values ('1','TARO','M');
insert into JSON.J_PERSON values ('2', 'HANA', 'F')
以下のようなクエリーを発行します。
SELECT USERID ,NAME ,ISMALE FROM JSON.J_PERSON_VIEW
以下のようにISMALEの値が文字列型として出力されます。
"1", "TARO", "1"
"2", "HANA", "0"
次に以下のようなクエリーを発行します。
SELECT JSON_OBJECT( 'userid':USERID ,'name':NAME ,'ismale':ISMALE ) FROM JSON.J_PERSON_VIEW;
以下のようなJSONデータが返ってきます。
{"userid":"1", "name":"TARO", "ismale":1}
{"userid":"2", "name":"HANA", "ismale":0}
この結果は誤りです。
ismaleに関しては、数字ではなくリテラル(文字)として返すのが正しい動作です。
この問題は2025.1以降のバージョンで修正されています。
記事
Toshihiko Minamoto · 2021年2月23日
# Java Business Host から PEX への移行
InterSystems IRIS 2020.1 および InterSystems IRIS for Health 2020.1 で [PEX](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=EPEX) がリリースされ、Java Business Host を使うよりも優れたかたちで Java プログラムをプロダクション環境に取り込めるようになりました。 PEX は、相互運用性のコンポーネントを構築するための API をすべて提供するほか、Java と .NET の両方で使用できます。 Java Business Host は非推奨となり、今後のリリースで廃止される予定です。
PEX を使うメリット
* デベロッパーはプロダクションのすべてのコンポーネントを、Java と .Net のどちらでも構築できる
* コンポーネント間で一層複雑なメッセージ構造の受け渡しができる
* シンプルな設定
* 開発のワークフローがシンプルな上に、ObjectScript を使う必要がない
ここからは、既存の Java Business Host のコードを PEX に移行する方法に注目します。
## 概要
PEX で使用されるクラスとインターフェースは、Java Business Host (JBH) のものとは異なります。 本記事では、その相違点を要約して解説しますが、詳細は[完全なドキュメント](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=EPEX_apiref)をご覧ください。
* [ビジネスサービスの変換](#Converting-a-Business-Service-from-Java-Business-Host-to-PEX)
* [ビジネスオペレーションの変換](#Converting-a-Business-Operation-from-Java-Business-Host-to-PEX)
* [設定](#Settings)
* [メッセージ](#Messages)
* [ログ](#Logging)
## ビジネスサービスを Java Business Host から PEX に変換する
PEX のビジネスサービスを構築するには、`com.intersystems.gateway.bh.BusinessService` の代わりに、`com.intersystems.enslib.pex.BusinessService` を実装する必要があります。
PEX で使用されるビジネスサービスの設計パターンは、サービスがスレッドを開始してメッセージを作成するというものから、サービスが定期的に呼び出される関数を実装してメッセージを作成するというものに一変しました。
JBH では、以下のようなコードが使われています。
```java
@Override
public boolean OnInit(Production p) throws Exception {
production = p;
if (messageThread == null) {
Messager messager = new Messager();
messageThread = new Thread(messager);
messageThread.start();
}
return true;
}
```
一方の PEX では、関数を 3 つ実装するだけで OK です。
```java
public void OnInit() throws Exception {
// 初期化
return;
}
public Object OnProcessInput(Object messageInput) throws Exception {
// ここで SendMessage() か SendMessageAsync() を呼び出します
return null;
}
public void OnTearDown() throws Exception {
// シャットダウン
return;
}
```
また、設定はどのように使用され、メッセージはどのように配信され、ログはどのように記録されるのかも変更する必要があります。 詳しくは後ほど解説します。
## ビジネスオペレーションを Java Business Host から PEX に変換する
PEX のビジネスオペレーションを構築するには、`com.intersystems.gateway.bh.BusinessOperation` の代わりに `com.intersystems.enslib.pex.BusinessOperation` を実装する必要があります。
ビジネスオペレーションの設計パターンは、JBH も PEX も構造的には同じですが、2 つのメインエントリーポイントへのパラメーターが変更されています。
### OnInit() の変更点
PEX の `OnInit()` はパラメーターを受け取りません。
### OnMessage() の変更点
PEX の場合、`OnMessage()` には、JBH で使用される `String` の代わりに、ジェネリック型の `Object` が与えられます。 これにより、プロダクションの作成者は好きなメッセージを渡すことができます。
JBH では、アプリケーションに以下のようなコードが使われていたのではないでしょうか
```java
public boolean OnMessage(String message) throws Exception {
// ビジネスロジックを実行
return true;
}
```
PEX では、パラメーターにジェネリック型の Java Object が使用されます。適切にキャストする必要がありますが、String を使った場合よりも一層複雑なメッセージを送信できます。 以下は、ファイルストリームであるリクエストを抽出する方法を示した例です。
```java
public Object OnMessage(Object request) throws Exception {
com.intersystems.jdbc.IRISObject streamContainer = (com.intersystems.jdbc.IRISObject)request;
com.intersystems.jdbc.IRISObject str = (com.intersystems.jdbc.IRISObject)streamContainer.get("Stream");
String originalFilename = (String)streamContainer.get("OriginalFilename");
Long contentSize = (Long)str.get("Size");
String content = (String)str.invoke("Read", contentSize);
// ビジネスロジックを実行
return null;
}
```
また、設定が使用される方法、メッセージが配信される方法、ログが記録される方法も変更する必要があります。 詳しくは後ほど解説します。
## 設定
設定の宣言が簡単になりました。
JBH では、設定は `SETTINGS` 文字列を使って宣言され、以下のようなコードで取り込まれていました。
```java
String setting = production.GetSetting("Min");
if (!setting.isEmpty()) {
min = Integer.parseInt(setting);
}
```
PEX の場合、設定は単純に public メンバフィールドとなります。 これらは、クラスがインスタンス化されるときに自動的に設定されます。
```java
public int Min = 0;
```
public メンバーフィールドは、Java の基本データ型 (String や int など) であれば、何でもプロダクション環境で設定できます。
## メッセージ
メッセージはよりパワフルに送信できます。 JBH では、メッセージは文字列として送信されます。 一方の PEX を使うと、メッセージは、 ObjectScript で定義されるオブジェクトの場合であれは、オブジェクト (IRISObject) として送信され、Java で定義されているクラスの場合であれば、`com.intersystems.enslib.pex.Message` のサブクラスとして送信されます。
JBH の場合は、以下のようなコードが使われます
```java
production.SendRequest(value.toString());
```
PEX の場合だと、以下のようなコードが使われます
```java
MyExampleMessageClass req = new MyExampleMessageClass("message to send");
SendRequestAsync(Target, req);
```
## ログ
ログ機能はすべて似たようなものですが、名前だけが違います。
PEX で情報メッセージをログするときは、`LOGINFO()` を使います。
```java
LOGINFO("Received message");
```
## オブジェクトのゲートウェイ
Java Business Host では、専用のゲートウェイが必要でしたが、 PEX では、Java ゲートウェイ 1 つで、Java のすべてのニーズに対応できます。 また、ゲートウェイはたくさん使うこともできます。 これはあなた次第です。 こちらの [Java ゲートウェイの手引き](https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=EJVG_intro) がおすすめです。
## 結論とフィードバック
まだ PEX を試していないという方は、ぜひぜひお試しください。 PEX を使えば、少ないコードで解決できるビジネスの問題の幅をぐっと広げることができます。また、今はすべての作業を .NET で実行できるようにもなりました。
JBH のアプリケーションを PEX へ移行させることに関するご質問や問題は、私か WRC までご連絡ください。
記事
Mihoko Iijima · 2021年10月12日
開発者の皆さん、こんにちは。
いつも使用しているユーザでアプリケーションや InterSystems 製品(IRIS/Caché/Ensemble/HealthShare) にアクセスしたとき、セキュリティ設定変更などの影響で急にアクセスできなくなった!という場合に、調査に便利な監査ログの参照方法をご紹介します。
ここでは、%Allロールを持つシステム管理ユーザ( _system や SuperUser )で管理ポータルにアクセスできる状態での確認方法をご紹介します。
監査ログですが、まずはシステムで監査が取られる設定になっているかご確認ください(通常無効化されている場合は、調査の時だけ有効に変更してください)。
管理ポータル > システム管理 > セキュリティ > 監査 > 監査を有効に
次に、アクセスできなくなった原因を探るため、以下のシステムイベントの監査を取得できるように変更します。
管理ポータル > システム管理 > セキュリティ > 監査 > システムイベントを構成以下のイベントの「状態変更」をクリックし、 Enabled に はい と表示されるようにします。
%System/%Login/LoginFailure
%System/%Security/Protect
この状態で、アクセスできない操作をもう1度試し、試した後で「監査データベースの閲覧」ページでエラーの内容を確認します。
管理ポータル > システム管理 > セキュリティ > 監査データベースの閲覧
以下例では、ターミナルにログインした時の監査ログの記録をご紹介します。
ログインに使用するユーザ名は test、 パスワード test、ロールに %Operator が設定されていて、管理ポータルの [システムオペレーション] メニューが利用できるユーザとします。
1) パスワードが異なるとき
ターミナルにアクセスしたときの表示は以下の通りです。
ユーザ名:test
パスワード:****
アクセスが拒否されました。
監査データベースの閲覧画面を再表示した時の一覧には、「プログラマモード ログイン失敗」と表示されています。
詳細を確認するため、「詳細」のリンクをクリックします。
「イベントデータ」の行にエラーメッセージが記録されています。
エラーメッセージ: エラー #798: パスワード 認証が失敗しました
エラー #952: パスワードが不正です
2) ユーザが存在しない時
存在しないユーザ(abc)でログインした場合は、以下のエラーが記録されます(この時も「プログラマモード ログイン失敗」と一覧に表示されます)。
詳細のリンクから「イベントデータ」を確認すると、以下のエラーメッセージが記録されています。
エラーメッセージ: エラー #798: パスワード 認証が失敗しました
エラー #838: ユーザ abc が存在しません
3) ユーザ名とパスワードはあっているのにターミナルにアクセスできない時(アクセス拒否 と出るとき)
ユーザ名、パスワードの指定はあっていそうなのに、ターミナルにアクセスできないエラーが出ているときの状態です。
以下のエラーが記録されます(この時も「プログラマモード ログイン失敗」と一覧に表示されます)。
詳細を確認します。
今回は、「エラーメッセージ: エラー #836: プログラマーアクセスの権限が不十分です」を出ています。
テストに使用しているユーザは %Operatorロールを持ちますが、ターミナルのアクセスに必要な %Developerロールを持っていません。そのため、アクセス権限不十分とエラーが出ています。
この他、使用しているユーザが「無効」になっている場合もアクセス拒否となり「プログラマーモード ログイン失敗」と表示され、詳細には以下のエラーメッセージが表示されます。
4) ターミナルにアクセスできるけど、特定のネームスペースにアクセスできない状態
ユーザ test の役割が変わり、開発者としてターミナルにアクセスできるユーザに変更する必要があるとします。
ここで、管理者がユーザ test から %Operator ロールを削除し、%Developer ロールを付与したとします。
管理ポータル > システム管理 > セキュリティ > ユーザ > testを選択 > ロール > %Developer付与
ユーザ名:test
パスワード:****
USER>
やっとターミナルにアクセスできました!
管理ポータルの [システムオペレーション] メニューの操作をルーチンで試そうと %SYS ネームスペースに移動します。
USER>set $namespace="%SYS"
SET $NAMESPACE="%SYS"
^
<PROTECT> *c:\intersystems\irishealth3\mgr\
USER>
残念・・。エラーです。
エラーの原因を監査ログを参照して確認します。
Protect のイベントが記録され「Attempt to access a protected resource」と表示されています。
詳細を確認します。
この記録は、mgr以下にある IRIS.dat(= IRISSYSデータベース)に対する <PROTECT> エラーが発生したことを意味します。
これは、ユーザ test から %Operator ロールを削除することで、IRISSYS データベースに対する READ と WRITE の許可がなくなったことが原因です。
%Developer ロールだけでは、アクセスしたいデータベースに対する許可が不足するため、追加でユーザ test に適切なデータベースの許可を付与する必要があります。
例のように、%SYS ネームスペースにアクセスしたい場合は、IRISSYSのデータベースロール(%DB_IRISSYS)を付与することでデータベースに対してREAD/WRITE の許可が追加できます。
再度、ターミナルにユーザ test でログインし直してから %SYS ネームスペースに移動し、試しにユーティリティを実行してみます。
ユーザ名:test
パスワード:****
USER>set $namespace="%SYS"
%SYS>do ^TASKMGR
1) タスク作成
2) タスク編集
3) タスク一覧
4) タスク削除
5) タスク一時停止
6) タスク再開
7) タスク実行
8) タスクリポート
9) タスクマネージャオプション
10) 終了
オプション?
うまく行きました。
いかがでしたでしょうか。
今まで使用していたユーザで急にアクセスできない!という状況になった時、セキュリティ設定に変更がなかったかどうかご確認ください。
もし変更した後アクセスできなくなった場合は、この記事で試したように、監査を使用してどんなエラーが発生しているか確認することができます。
監査についてのドキュメントもあります。ぜひご参照ください。
最後に、普段監査を使用されていない環境は、調査が終わったら「無効化」することをお忘れなく!
記事
Toshihiko Minamoto · 2021年2月2日
この記事は Caché データベースの内部構造を説明したこちらの[記事](https://jp.community.intersystems.com/node/485976)の続編です。 そちらの記事では、様々なブロックタイプ、それぞれのつながりやグローバルとの関係について説明しました。 純粋に理論を述べた記事でした。 ブロックツリーを視覚化するのに役立つ[プロジェクト](https://github.com/daimor/CacheBlocksExplorer)を作成しましたので、この記事ではその仕組みを詳しく説明します。
[](https://hsto.org/files/65a/263/1ca/65a2631ca90840e1b1153abeff540c12.png)
デモを行うために、新しいデータベースを作成しましたが、Caché のデフォルト機能としてすべての新しいデータベースで初期化されるグローバルは消去しています。 それでは、シンプルなグローバルを作成しましょう。
set ^colors(1)="red"
set ^colors(2)="blue"
set ^colors(3)="green"
set ^colors(4)="yellow"

作成されたグローバルのブロックを表す画像をご覧ください。 これはシンプルなものなので、その説明は Type 9 のブロック (グローバルカタログのブロック) に記載されています。 次にくるのが、「上位ポインタと下位ポインタ」のブロック (Type 70) です (グローバルツリーはまだ浅いため)。ここでは、まだ 8KB の単一のブロックに収まるデータブロックへのポインタを使用できます。
それでは、単一のブロックには収まりきらないほどの数の値を別のグローバルに書き込んでみます。そして、最初のブロックに収まらなかった新しいデータブロックにポイントするポインタブロックの中に新しいノードが表示されます。
それでは、それぞれ 1000 文字を持つ値を 50 個書き込んでみましょう。 このデータベースのブロックサイズは 8192 バイトであることを覚えておいてください。
set str=""
for i=1:1:1000 {
set str=str_"1"
}
for i=1:1:50 {
set ^test(i)=str
}
quit
下の画像をご覧ください。

ポインタブロックレベルでデータブロックにポイントするノードがいくつかあります。 各データブロックには、次のブロックをポイントするポインタがあります (「適切なリンク」)。 Offset は、このデータブロック内で占有されているバイト数をポイントしています。
それでは、ブロックの分割をシミュレートしてみましょう。 ブロックの合計サイズが 8KB をオーバーしてしまうほどの数の値をブロックに追加しましょう。それにより、ブロックは半分に分割されます。
サンプルコード
set str=""
for i=1:1:1000 {
set str=str_"1"
}
set ^test(3,1)=str
set ^test(3,2)=str
set ^test(3,3)=str
結果は以下の通りです。

ブロック #50 が分割され、新しいデータが入っているのが分かります。 ブロック #50 から取り出された値はブロック #58 に置かれ、このブロックにポイントするポインタがポインタブロックに表示されているのが分かります。 他のブロックに変化はありません。
**長い文字列を使った例**
8KB (データブロックのサイズ) よりも長い文字列を使うと、「長いデータ」で構成されるブロックができます。 そのような状況は、例えば、文字列を 10000 バイトとして書き込んでシミュレートします。
サンプルコード
set str=""
for i=1:1:10000 {
set str=str_"1"
}
for i=1:1:50 {
set ^test(i)=str
}
結果を見てみましょう。

結果としては、新しいグローバルノードは加えずに、値を変更しただけなので、画像に表示されているブロック構造に変更はありません。 しかし、すべてのブロックで、Offset の値 (占有されているバイト数) に変化がありました。 例えば、ブロック #51 の Offset の値は、7088 から 172 に変わっています。 新しい値がブロックに収まらない場合は、データの最後のバイトへのポインタが変更されるということが分かりました。しかし、データはどこに行ったのでしょう? 現時点では、「大きなブロック」に関する情報を示す技術的な可能性はありません。 それでは、^REPAIR ツールを使って、ブロック #51 の新しいデータに関する情報を取得してみましょう。

このツールの仕組みを詳しく説明いたします。 右側のブロック #52 へのポインタがあり、同じ番号が次のノードの親ポインタブロックで指定されているのが分かります。 グローバルの照合順序は Type 5 に設定されています。 長い文字列を持つノードの数は 7 個です。 場合によっては、1 つのブロックの中に、いくつかのノードのデータ値と別のノードの長い文字列の両方が含まれる場合があります。 また、次のブロックの先頭で予測できる次のポインタ参照も表示されています。
長い文字列のブロックについて: キーワード「BIG」がグローバルの値をとして指定されているのが分かります。 それは、データが実際には「大きなブロック」に保管されていることを意味します。 同じ行には、含まれている文字列の長さの合計とこの値を保管するブロックの一覧が表示されています。 それでは、ブロック #73 (長い文字列のブロック) を見てみましょう。

残念ながら、このブロックはエンコードされた状態で表示されています。 しかし、ブロックヘッダーのサービス情報 (長さは常に 28 バイト) に続いて、私たちのデータが表示されているのが分かります。 データ型が分かっていると、ヘッダーの内容をとても簡単にデコードできます。
位置
値
説明
コメント
0-3
E4 1F 00 00
データの最後をポイントする Offset
8164 バイトとヘッダーの 28 バイトを合わせて合計 8192 バイトあり、ブロックは満タンです。
4
18
ブロックタイプ
記憶にあるかと思いますが、24 は長い文字列の型指定子です。
5
05
照合順序
照合順序 5 は「標準の Caché」を意味します
8-11
4A 00 00 00
適切なリンク
ここは 74 になっています。記憶にあるかと思いますが、値はブロック #73 と #74 に保管されます。
ブロック #51 のデータはわずか 172 バイトしか占有していないことを覚えていますか? 大きな値を保存したにも関わらずです。 つまり、有効なデータがわずか 172 バイトとなり、ブロックはほぼ空になったように思えますが、それでも 8KB を占有しているのです! そのような場合、空きスペースには新しい値が入力されることが分かりましたが、Caché ではそのようなグローバルを圧縮することもできます。 [%Library.GlobalEdit](http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?APP=1&LIBRARY=%25SYS&CLASSNAME=%25Library.GlobalEdit) クラスに CompactGlobal メソッドがあるのはそのためです。 このメソッドの効率を確認するために、サンプルコードを使って大規模のデータを作成してみましょう。例えば、ノードを 500 個作成します。
こちらのコードを実行します。
kill ^test
for l=1000,10000 {
set str=""
for i=1:1:l {
set str=str_"1"
}
for i=1:1:500 {
set ^test(i)=str
}
}
quit
すべてのブロックを表示するのは控えますが、要点は理解していただけると思います。 データブロックはたくさんありますが、ノードの数は少なくなっています。

以下のように CompactGlobal メソッドを実行します
write ##class(%GlobalEdit).CompactGlobal("test","c:\intersystems\ensemble\mgr\test")
結果を見てみましょう。 ポインタブロックにはノードが 2 個しかありません。つまり、最初はポインタブロックにノードが 72 個もあったのに対し、実際はすべての値が 2 個のノードに移動されているのです。 従い、70 個ものノードを取り除いたことになり、ブロックの読み取り操作を行う回数が減ったため、グローバルをイテレーションしてデータにアクセスする時間が短縮されました。

CompactGlobal には、グローバルの名前やデータベース、ターゲットとするフィル値 (デフォルトは 90%) など、様々なパラメーターを渡すことができます。 そして、Offset (占有されているバイト数) の値は 7360 となり、デフォルトのフィル値 90% に近くなったことが分かります。 関数には、処理されたメガバイト数や圧縮後のメガバイト数など、複数の出力パラメーターがあります。 以前、グローバルは、今や廃止ツールとされる ^GCOMPACT を使って圧縮されていました。
ちなみに、ブロックが部分的に満たされた状態で変化しないというのはいたって普通のことです。 また、グローバルを圧縮するのは好ましくないと考えられる場合もあります。 ですが、例えば、ほぼ読み取るだけで、変更することが滅多にないというグローバルは、圧縮すると良いかもしれません。 但し、グローバルがしょっちゅう変更される場合なら、データブロックの密度が低いと頻繁にブロックを分割する手間が省けるほか、新しいデータもより素早く保存できます。
本記事のまたさらに次の続編では、InterSystems School 2015 で初の開催となった InterSystems [ハッカソン (hackathon)](http://writeimagejournal.com/?p=1912) の最中に導入された、私自作のプロジェクトのまた別の機能「データベースブロックの分布状況を表すマップ」とその実用的な活用方法について解説いたします。
記事
Toshihiko Minamoto · 2021年11月9日
IRISインターオペラビリティのメッセージビューワで何かを変更できるとしたら、何を変更しますか?
「Dashboard IRIS History Monitor」の記事を公開したところ、素晴らしいフィードバックやリクエストをいただきました。 中には、メッセージビューワの拡張に関するリクエストがありました。
まだプロジェクトを確認していない方は、ぜひご覧ください。絶対に見る価値がありますし、[2019年の最高のInterSystems Open Exchange開発者およびアプリケーション](https://community.intersystems.com/post/best-intersystems-open-exchange-developers-and-applications-2019)の1つとしてブロンズ賞を受賞しました。
「新しい」メッセージビューワに含めようと思う機能についてのアイデアを書き留め始めましたが、これらのリソースをどのようにすれば素早く簡単に見せることができるのでしょうか。
まずは、 一般的に、相互運用性の本番環境をセットアップし、[ドキュメント](https://docs.intersystems.com/iris20191j/csp/docbook/Doc.View.cls?KEY=EGDV_deploying)の指示のとおりに、ターゲットシステムにエクスポートしてデプロイすることから始めます。 これは私があまり好まないプロセスです。 特に何か悪いというわけではありませんが、 コードを使ってすべてを行う考えがあるためです。
誰かがこういったプロジェクトを実行するたびに、次のように開始することを期待しています。
`$ docker-compose build`
`$ docker-compose up -d`
いかがでしょうか!!!
たったこれだけのステップを思い浮かべながら、InterSystemsコミュニティを調べ始めると、いくつかのヒントが見つかりました。 ある投稿では、私が自問していた質問が挙げられていました。「[ルーチンを使って本番環境を作成するにはどうすればよいのか。](https://community.intersystems.com/post/how-create-productions-routine)」
その投稿の中で、@Eduard.Lebedyuk が、コードを使って本番環境を作成する方法を次のように回答しています。
「本番クラスを自動的に作成するには、次を行う必要があります。
1. テストプロダクション用の%Dictionary.ClassDefinitionオブジェクトを作成します。
2. Ens.Config.Productionオブジェクトを作成します。
3. %Dictionary.XDataDefinitionを作成します。
4. (2) を (3) にシリアル化します。
5. XData (3) を (1) に挿入します。
6. (1) を保存してコンパイルします。」
@Jenny Amesのコメントにも、次のように書かれていました。
「私たちがよくお勧めしているベストプラクティスは、逆方向に構築することです。 ビジネスオペレーションを先に構築してから、ビジネスプロセス、そしてビジネスサービスを構築していく方法です...」
というわけで、早速やってみましょう!
##
リクエスト、ビジネスオペレーション、およびビジネスサービス
クラス**diashenrique.messageviewer.util.InstallerProduction.cls**は、名前から想像できるように、プロダクションのインストールを担当するクラスです。 インストーラのマニフェストは、そのクラスからClassMethod **Install**を呼び出します。
/// 拡張ビューワの表示機能にプロダクションをインストールするヘルパー
ClassMethod Install() As %Status
{
Set sc = $$$OK
Try {
Set sc = $$$ADDSC(sc,..InstallProduction()) quit:$$$ISERR(sc)
Set sc = $$$ADDSC(sc,..GenerateMessages()) quit:$$$ISERR(sc)
Set sc = $$$ADDSC(sc,..GenerateUsingEnsDirector()) quit:$$$ISERR(sc)
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
クラスメソッド**InstallProduction**は、次を作成することで、プロダクションを作成するためのメインの構造をまとめます。
* リクエスト
* ビジネスオペレーション
* ビジネスサービス
* 相互運用性プロダクション
コードを使用して相互運用性プロダクションを作成しようと考えているため、完全なコーディングモードに移行して、リクエスト、ビジネスオペレーション、およびビジネスサービスの全クラスを作成しましょう。 これを行うには、いくつかのInterSystemsライブラリパッケージを広範に使用します。
* %Dictionary.ClassDefinition
* %Dictionary.PropertyDefinition
* %Dictionary.XDataDefinition
* %Dictionary.MethodDefinition
* %Dictionary.ParameterDefinition
クラスメソッド**InstallProduction**は、次のコードを使用して、**Ens.Request**を継承した2つのクラスを作成します。
Set sc = $$$ADDSC(sc,..CreateRequest("diashenrique.messageviewer.Message.SimpleRequest","Message")) quit:$$$ISERR(sc)
Set sc = $$$ADDSC(sc,..CreateRequest("diashenrique.messageviewer.Message.AnotherRequest","Something")) quit:$$$ISERR(sc)
ClassMethod CreateRequest(classname As %String, prop As %String) As %Status [ Private ]
{
New $Namespace
Set $Namespace = ..#NAMESPACE
Set sc = $$$OK
Try {
Set class = ##class(%Dictionary.ClassDefinition).%New(classname)
Set class.GeneratedBy = $ClassName()
Set class.Super = "Ens.Request"
Set class.ProcedureBlock = 1
Set class.Inheritance = "left"
Set sc = $$$ADDSC(sc,class.%Save())
#; create adapter
Set property = ##class(%Dictionary.PropertyDefinition).%New(classname)
Set property.Name = prop
Set property.Type = "%String"
Set sc = $$$ADDSC(sc,property.%Save())
Set sc = $$$ADDSC(sc,$System.OBJ.Compile(classname,"fck-dv"))
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
では、**Ens.BusinessOperation**を継承したビジネスオペレーションのクラスを作成しましょう。
Set sc = $$$ADDSC(sc,..CreateOperation()) quit:$$$ISERR(sc)
このクラスを作成するほかに、MessageMapとメソッドConsumeを作成します。
ClassMethod CreateOperation() As %Status [ Private ]
{
New $Namespace
Set $Namespace = ..#NAMESPACE
Set sc = $$$OK
Try {
Set classname = "diashenrique.messageviewer.Operation.Consumer"
Set class = ##class(%Dictionary.ClassDefinition).%New(classname)
Set class.GeneratedBy = $ClassName()
Set class.Super = "Ens.BusinessOperation"
Set class.ProcedureBlock = 1
Set class.Inheritance = "left"
Set xdata = ##class(%Dictionary.XDataDefinition).%New()
Set xdata.Name = "MessageMap"
Set xdata.XMLNamespace = "http://www.intersystems.com/urlmap"
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("Consume")
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("Consume")
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("")
Do class.XDatas.Insert(xdata)
Set sc = $$$ADDSC(sc,class.%Save())
Set method = ##class(%Dictionary.MethodDefinition).%New(classname)
Set method.Name = "Consume"
Set method.ClassMethod = 0
Set method.ReturnType = "%Status"
Set method.FormalSpec = "input:diashenrique.messageviewer.Message.SimpleRequest,&output:Ens.Response"
Set stream = ##class(%Stream.TmpCharacter).%New()
Do stream.WriteLine(" set sc = $$$OK")
Do stream.WriteLine(" $$$TRACE(input.Message)")
Do stream.WriteLine(" return sc")
Set method.Implementation = stream
Set sc = $$$ADDSC(sc,method.%Save())
Set sc = $$$ADDSC(sc,$System.OBJ.Compile(classname,"fck-dv"))
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
相互運用性プロダクションを作成する直前のステップでは、ビジネスサービスクラスを作成しましょう。
Set sc = $$$ADDSC(sc,..CreateRESTService()) quit:$$$ISERR(sc)
このクラスにはHttpリクエストを受信するためのUrlMapとRoutesがあります。
ClassMethod CreateRESTService() As %Status [ Private ]
{
New $Namespace
Set $Namespace = ..#NAMESPACE
Set sc = $$$OK
Try {
Set classname = "diashenrique.messageviewer.Service.REST"
Set class = ##class(%Dictionary.ClassDefinition).%New(classname)
Set class.GeneratedBy = $ClassName()
Set class.Super = "EnsLib.REST.Service, Ens.BusinessService"
Set class.ProcedureBlock = 1
Set class.Inheritance = "left"
Set xdata = ##class(%Dictionary.XDataDefinition).%New()
Set xdata.Name = "UrlMap"
Set xdata.XMLNamespace = "http://www.intersystems.com/urlmap"
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("")
Do xdata.Data.WriteLine("")
Do class.XDatas.Insert(xdata)
Set sc = $$$ADDSC(sc,class.%Save())
#; create adapter
Set adapter = ##class(%Dictionary.ParameterDefinition).%New(classname)
Set class.GeneratedBy = $ClassName()
Set adapter.Name = "ADAPTER"
Set adapter.SequenceNumber = 1
Set adapter.Default = "EnsLib.HTTP.InboundAdapter"
Set sc = $$$ADDSC(sc,adapter.%Save())
#; add prefix
Set prefix = ##class(%Dictionary.ParameterDefinition).%New(classname)
Set prefix.Name = "EnsServicePrefix"
Set prefix.SequenceNumber = 2
Set prefix.Default = "|demoiris"
Set sc = $$$ADDSC(sc,prefix.%Save())
Set method = ##class(%Dictionary.MethodDefinition).%New(classname)
Set method.Name = "SendMessage"
Set method.ClassMethod = 0
Set method.ReturnType = "%Status"
Set method.FormalSpec = "input:%Library.AbstractStream,&output:%Stream.Object"
Set stream = ##class(%Stream.TmpCharacter).%New()
Do stream.WriteLine(" set sc = $$$OK")
Do stream.WriteLine(" set request = ##class(diashenrique.messageviewer.Message.SimpleRequest).%New()")
Do stream.WriteLine(" set data = {}.%FromJSON(input)")
Do stream.WriteLine(" set request.Message = data.Message")
Do stream.WriteLine(" set sc = $$$ADDSC(sc,..SendRequestSync(""diashenrique.messageviewer.Operation.Consumer"",request,.response))")
Do stream.WriteLine(" return sc")
Set method.Implementation = stream
Set sc = $$$ADDSC(sc,method.%Save())
Set method = ##class(%Dictionary.MethodDefinition).%New(classname)
Set method.Name = "SendSomething"
Set method.ClassMethod = 0
Set method.ReturnType = "%Status"
Set method.FormalSpec = "input:%Library.AbstractStream,&output:%Stream.Object"
Set stream = ##class(%Stream.TmpCharacter).%New()
Do stream.WriteLine(" set sc = $$$OK")
Do stream.WriteLine(" set request = ##class(diashenrique.messageviewer.Message.AnotherRequest).%New()")
Do stream.WriteLine(" set data = {}.%FromJSON(input)")
Do stream.WriteLine(" set request.Something = data.Something")
Do stream.WriteLine(" set sc = $$$ADDSC(sc,..SendRequestSync(""diashenrique.messageviewer.Operation.Consumer"",request,.response))")
Do stream.WriteLine(" return sc")
Set method.Implementation = stream
Set sc = $$$ADDSC(sc,method.%Save())
Set sc = $$$ADDSC(sc,$System.OBJ.Compile(classname,"fck-dv"))
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
## Visual Studioコードの使用
%Dictionaryパッケージを使用してクラスを作成するのは困難な場合があり、読みにくくもありますが、非常に便利です。 コードの可読性を良くしてアプローチをもう少しわかりやすくするために、Visual Studioコードを使用して新しいリクエスト、ビジネスサービス、およびビジネスオペレーションクラスを作成することにします。
* diashenrique.messageviewer.Message.SimpleMessage.cls
* diashenrique.messageviewer.Operation.ConsumeMessageClass.cls
* diashenrique.messageviewer.Service.SendMessage.cls
Class diashenrique.messageviewer.Message.SimpleMessage Extends Ens.Request [ Inheritance = left, ProcedureBlock ]
{
Property ClassMessage As %String;
}
Class diashenrique.messageviewer.Operation.ConsumeMessageClass Extends Ens.BusinessOperation [ Inheritance = left, ProcedureBlock ]
{
Method Consume(input As diashenrique.messageviewer.Message.SimpleMessage, ByRef output As Ens.Response) As %Status
{
Set sc = $$$OK
$$$TRACE(pRequest.ClassMessage)
Return sc
}
XData MessageMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
Consume
}
}
Class diashenrique.messageviewer.Service.SendMessage Extends Ens.BusinessService [ ProcedureBlock ]
{
Method OnProcessInput(input As %Library.AbstractStream, ByRef output As %Stream.Object) As %Status
{
Set tSC = $$$OK
// リクエストメッセージを作成
Set request = ##class(diashenrique.messageviewer.Message.SimpleMessage).%New()
// リクエストメッセージプロパティに値をセット
Set request.ClassMessage = input
// ビジネスプロセスに同期呼び出しを行い、レスポンスメッセージをレスポンスとして使用
Set tSC = ..SendRequestSync("diashenrique.messageviewer.Operation.ConsumeMessageClass",request,.output)
Quit tSC
}
}
コードの可読性の観点では、大きな差があります!
## 相互運用性プロダクションの作成
相互運用性プロダクションを仕上げましょう。 これを行うには、プロダクションクラスを作成してから、それをビジネスオペレーションとサービスクラスに関連付けます。
Set sc = $$$ADDSC(sc,..CreateProduction()) quit:$$$ISERR(sc)
ClassMethod CreateProduction(purge As %Boolean = 0) As %Status [ Private ]
{
New $Namespace
Set $Namespace = ..#NAMESPACE
Set sc = $$$OK
Try {
#; create new production
Set class = ##class(%Dictionary.ClassDefinition).%New(..#PRODUCTION)
Set class.ProcedureBlock = 1
Set class.Super = "Ens.Production"
Set class.GeneratedBy = $ClassName()
Set xdata = ##class(%Dictionary.XDataDefinition).%New()
Set xdata.Name = "ProductionDefinition"
Do xdata.Data.Write("")
Do class.XDatas.Insert(xdata)
Set sc = $$$ADDSC(sc,class.%Save())
Set sc = $$$ADDSC(sc,$System.OBJ.Compile(..#PRODUCTION,"fck-dv"))
Set production = ##class(Ens.Config.Production).%OpenId(..#PRODUCTION)
Set item = ##class(Ens.Config.Item).%New()
Set item.ClassName = "diashenrique.messageviewer.Service.REST"
Do production.Items.Insert(item)
Set sc = $$$ADDSC(sc,production.%Save())
Set item = ##class(Ens.Config.Item).%New()
Set item.ClassName = "diashenrique.messageviewer.Operation.Consumer"
Do production.Items.Insert(item)
Set sc = $$$ADDSC(sc,production.%Save())
Set item = ##class(Ens.Config.Item).%New()
Set item.ClassName = "diashenrique.messageviewer.Service.SendMessage"
Do production.Items.Insert(item)
Set sc = $$$ADDSC(sc,production.%Save())
Set item = ##class(Ens.Config.Item).%New()
Set item.ClassName = "diashenrique.messageviewer.Operation.ConsumeMessageClass"
Do production.Items.Insert(item)
Set sc = $$$ADDSC(sc,production.%Save())
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
プロダクションクラスをビジネスオペレーションとサービスクラスに関連付けるために、クラス**Ens.Config.Item**を使用します。 これは、クラスの作成に%Dictionaryパッケージを使用したのか、VS Code、Studio、またはAtelierを使用したかに関係なく使用できます。
いずれにしても、達成できました! コードを使用して相互運用性プロダクションを作成できました。
ただし、このコードの元の目的を忘れてはいけません。拡張メッセージビューワの機能を示すプロダクションとメッセージを作成するという目的です。 以降のクラスメソッドを使用して、両方のビジネスサービスを実行し、メッセージを生成します。
### %Net.HttpRequestを使用たメッセージの生成:
ClassMethod GenerateMessages() As %Status [ Private ]
{
New $Namespace
Set $Namespace = ..#NAMESPACE
Set sc = $$$OK
Try {
Set action(0) = "/demoiris/send/message"
Set action(1) = "/demoiris/send/something"
For i=1:1:..#LIMIT {
Set content = { }
Set content.Message = "Hi, I'm just a random message named "_$Random(30000)
Set content.Something = "Hi, I'm just a random something named "_$Random(30000)
Set httprequest = ##class(%Net.HttpRequest).%New()
Set httprequest.SSLCheckServerIdentity = 0
Set httprequest.SSLConfiguration = ""
Set httprequest.Https = 0
Set httprequest.Server = "localhost"
Set httprequest.Port = 9980
Set serverUrl = action($Random(2))
Do httprequest.EntityBody.Write(content.%ToJSON())
Set sc = httprequest.Post(serverUrl)
Quit:$$$ISERR(sc)
}
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
### EnsDirectorを使用したメッセージの生成:
ClassMethod GenerateUsingEnsDirector() As %Status [ Private ]
{
New $Namespace
Set $Namespace = ..#NAMESPACE
Set sc = $$$OK
Try {
For i=1:1:..#LIMIT {
Set tSC = ##class(Ens.Director).CreateBusinessService("diashenrique.messageviewer.Service.SendMessage",.tService)
Set message = "Message Generated By CreateBusinessService "_$Random(1000)
Set tSC = tService.ProcessInput(message,.output)
Quit:$$$ISERR(sc)
}
}
Catch (err) {
Set sc = $$$ADDSC(sc,err.AsStatus())
}
Return sc
}
}
コードは以上です。 完全なプロジェクトは、[https://github.com/diashenrique/iris-message-viewer](https://github.com/diashenrique/iris-message-viewer.)をご覧ください。
## プロジェクトの実行
では、プロジェクトの実際の動作を確認しましょう。 まず、git cloneまたはgit pullで、任意のローカルディレクトリにリポジトリを作成します。
`git clone https://github.com/diashenrique/iris-message-viewer.git`
次に、このディレクトリでターミナルを開き、次を実行します。
`docker-compose build`
最後に、プロジェクトでIRISコンテナを実行します。
`docker-compose up -d`
さらに、を使用して管理ポータルにアクセスします。 次の画像のように、相互運用性のネームスペースMSGVIEWERが表示されます。

そしてこれが、私たちの愛らしいプロダクションです。2つのビジネスサービスと2つのビジネスオペレーションがあります。

非常にたくさんのメッセージがあります。

カスタムメッセージビューワですべてが稼働しているので、その機能を見てみましょう。
## 拡張メッセージビューワ
相互運用性プロダクションに有効になっているネームスペースのみが表示されることに注意してください。
[](https://raw.githubusercontent.com/diashenrique/iris-message-viewer/master/images/InteroperabilityNamespace.png)
拡張メッセージビューワには、さまざまなフィルタの作成、nレベルへの列のグループ化、Excelへのエクスポートなどを行える機能と柔軟性が備わっています。

さまざまなフィルタを使用して、必要な結果を得ることができます。 また、Shiftキーを押しながら列のヘッダーをクリックすると、複数の並べ替えを使用することも可能です。 データグリッドをExcelにエクスポートすることもできるのです!


さらに、フィルタビルダーオプションを使用して、複雑なフィルタを作成することができます。
使用できる任意の列に対してデータをグループ化し、必要なnレベルを使用して情報をまとめることができます。 デフォルトでは、このグループはDate Created(作成日)フィールドを使用して作成されます。

また、列を選択できる機能があります。 次のページには、Ens.MessageHeaderのすべての列があります。デフォルトの列のみが初期ビューに表示されていますが、 「Column Chooser」(列選択)ボタンを使って、ほかの列を選択することができます。

すべてのグループはワンクリックで折りたたみと展開が可能です。

SessionId(セッションID)フィールドの情報には、ビジュアルトレース機能へのリンクがあります。

必要に応じて、メッセージを再送することができます。 必要なメッセージを選択し、Resend をクリックするだけで再送信は完了です。 この機能には、次のクラスメソッドが使用されています。
`##class(Ens.MessageHeader).ResendDuplicatedMessage(id)`

最後に、前述のように、データグリッドをExcelにエクスポートすることができます。

Excelの結果には、キャッシュサーバーページ(CSP)に定義されているものと同じフォーマット、コンテンツ、およびグループが表示されます。
追伸: この問題への取り組みで大いに助けてくれた@Renan.Lourencoに、特に深くお礼申し上げます。
記事
Mihoko Iijima · 2021年6月17日
開発者の皆さん、こんにちは!
2023/2/21追記
チュートリアルページが新しくなり「Developer Hub」に変わりました!(ユーザ登録不要です)
チュートリアルの種類や使い方については、「InterSystems Developer Hub:クリック1回で開始できるチュートリアル(4種)のご紹介」をご参照ください。
この記事では、GettingStarted ページのチュートリアルを試す環境として利用できる、無料体験環境 Sandbox の開始手順についてご紹介します。
GettingStarted ページで何ができるのか?については、前の記事でご紹介しています。ぜひご参照ください。
どのチュートリアルからでも Sandbox の作成やアクセス情報を確認することができます。
この記事では、Full Stack Tutorial を試す流れで Sandbox を作成する手順をご紹介します。
1) REGISTERボタンがある画面へ移動
画面左目メニューで、Full Stack Tutorial > Part1:Creating databases with SQL をクリックし、画面右側の「REGISTER」ボタンをクリックすると、ユーザ情報登録画面に移動します。
2) ユーザ情報登録
Sandbox 作成時、以下図の情報をご記入いただきます(* の付いた項目は必須です)。
実際の画面は縦長の画面ですが、図解用に左右に画面を貼り付けています。赤い四角で囲われた項目の入力とチェック、ご記入が終わったら「Continue」ボタンをクリックしてください。
この後、ご登録時にご記入いただいたメールアドレスへトークンを送付します。メールをご確認ください。
3) トークンの入力とパスワードの設定
登録したメールアドレスにトークンが届きます。テキストボックスにトークンを記入し、パスワード設定画面に移動します。
パスワードの設定完了でユーザ登録も完了します。
最後に、「Return to Login」のリンクをクリックします。
4) Sandbox へログインと環境作成
LOGINボタンを押すとユーザ登録情報を使用して自動的にログインが行われます。
(ユーザ名、パスワードの入力画面が出た場合は、ユーザ登録時のメールアドレスと設定されたパスワードでログインを行ってください)
LOGIN後、環境作成用の「PROVISION SANDBOX」ボタンが表示されるので、クリックします。
環境構築には数分かかるので、しばらくそのままでお待ちください。
Sandbox の作成が完了すると、Sandbox 専用 IDE へのリンクと、IRIS の管理ポータルへのリンクが表示されます。
Sandbox へのアクセス情報は、GettingStarted ページのどのチュートリアルからでも参照できます。
作成した Sandbox は72時間後に消去されますので、消去された場合は「PROVISION SANDBOX」ボタンを押すことで新環境を作成できます。
72時間経過で自動削除される場合、それまで操作されていた内容も消去されます。予めご了承ください。
以上で、Sandbox の作成方法は終了です。
次は、いよいよチュートリアルの開始方法をご紹介します!
記事
Megumi Kakechi · 2024年5月24日
こちら の記事では、LinuxでJDBC接続を行う方法 をご紹介しました。
今回は、SSL/TLS を使用するように InterSystems IRIS スーパーサーバを構成 した IRIS に対して、JDBCで SSL/TLS 接続をする方法をご紹介します。
LinuxでJDBC接続を行う方法 の記事で紹介している手順で、SSL/TLS なしでJDBC接続できる環境を用意していることを前提にご説明します。
手順は以下のようになります。手順の詳細は、この後で説明します。
1.CA証明書を用意します
2.Java キーストアに証明書をインポートします
3.Java ファイルを含むディレクトリに、SSLConfig.properties という名前の構成ファイルを作成ます
4.Java のコードに SSL/TLS の使用を指定する設定を追加します
1.CA証明書を用意します
最初に、CA証明書を用意します。証明書に問題がないか証明書情報を確認します。※ ***.***.***.*** :接続先IRISサーバのIPアドレス
# openssl s_client -connect ***.***.***.***:1972 -showcerts -CAfile /home/ec2-user/ca_certificate.crt < /dev/null
CONNECTED(00000003)
:
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
DONE
「Verify return code: 0 (ok)」が返れば、CA証明書に問題はありません。
2.以下のコマンドで、Java キーストアに証明書をインポートします
実行ディレクトリに keystore.jks ファイルが生成されます。
$ su -
# keytool -importcert -file /path-to-cert/ca_certificate.crt -keystore keystore.jks
Enter keystore password: <-- 任意のパスワード
Re-enter new password: <-- 任意のパスワード(再入力)
Trust this certificate? [no]: yes <-- Yes
Certificate was added to keystore
#
※keytool 実行可能ファイルは、JDK ディストリビューションに同梱されています。
3.Java ファイルのあるディレクトリに、SSLConfig.properties という名前の構成ファイルを作成します
SSLConfig.properties ファイルには、次の2つのプロパティを含めます。
trustStore=path-to-keystore/keystore.jks <-- 2 で作成した keystore.jks のファイルパス
trustStorePassword=keystore-password <-- 2 で設定したパスワード
※クライアント認証が必要な場合、キーストアやその他構成ファイルの詳細については、こちら のドキュメントをご覧ください。
4.Java のコードに SSL/TLS の使用を指定する設定を追加します
※%SuperServerの設定をした接続先のIRISでは、「スーパーサーバSSL/TLSサポート」を「有効」または「必須」に設定してください。
こちらのサンプルでは、DriverManager クラスを使用した接続テスト を行います。
import java.sql.*;
public class JDBCSample_TLS {
public static void main(String[] str) throws Exception {
String url = "jdbc:IRIS://***.***.***.***:1972/USER/";
java.util.Properties prop = new java.util.Properties();
prop.put("connection security level", "10"); // SSL/TLS 接続にはこの設定が必要です
prop.put("user", "_System");
prop.put("password", "SYS");
// Replace _SYSTEM and SYS with a username and password on your system
Connection connection = DriverManager.getConnection(url,prop);
Statement statement = connection.createStatement();
String query = "SELECT top 5 TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES";
ResultSet resultSet = statement.executeQuery(query);
System.out.println("Printing out contents of SELECT query: ");
while (resultSet.next()) {
System.out.println(resultSet.getString(1) + ", " + resultSet.getString(2) + ", " + resultSet.getString(3));
}
resultSet.close();
statement.close();
connection.close();
}
}
コンパイル&実行します。
# javac JDBCSample_TLS.java
# java JDBCSample_TLS
Printing out contents of SELECT query:
%CSP_Util, CSPLogEvent, SYSTEM TABLE
%CSP_Util, Performance, SYSTEM TABLE
%Calendar, Hijri, SYSTEM TABLE
%Compiler_Informix, ConversionRule, SYSTEM TABLE
%Compiler_Informix, ImportedObject, SYSTEM TABLE
※IRISDataSource を使用する場合は以下のようになります。
import com.intersystems.jdbc.*;
import java.sql.*:;
public class JDBCSample_TLS {
public static void main(String[] str) throws Exception {
String url = "jdbc:IRIS://***.***.***.***:1972/USER/";
IRISDataSource ds = new IRISDataSource();
ds.setURL(url);
ds.setUser("SYS");
ds.setPassword("_System");
ds.setConnectionSecurityLevel(10); // SSL/TLS 接続にはこの設定が必要です
Connection connection = ds.getConnection();
// 以下、DriverManager のサンプルと同じ
:
詳細は以下のドキュメントをご覧ください。Securing the JDBC Connection with TLS
記事
Megumi Kakechi · 2023年2月12日
これは InterSystems FAQ サイトの記事です。
日時検索で、TimeStamp型のクエリのパフォーマンスが出ない場合の対処法をご紹介します。
%TimeStamp データ型形式 (yyyy-mm-dd hh:mm:ss.ffff)は、人が読めることを目的とした ODBC 日付形式の文字列として格納されます。そのため、どうしてもデータサイズが大きくなりクエリの実行に時間がかかってしまいます。%TimeStamp型のプロパティにインデックスを作成している場合にも、クエリオプティマイザはそのインデックスを優先して最適化するようにはなっておりません。
IRISでは、POSIX 時刻(※)をサポートしているため、TimeStamp値を表すのに %Library.PosixTime データ型形式を使用できます。こちらは、Integer型で保存され、%Timestampの高性能な代替法となります。
※POSIX 時間は、協定世界時 (UTC) 1970年1月1日 00:00:00(UNIXエポック)からの経過秒数として表されます。 1970-01-01 00:00:00より前の日付は、負の論理値で表されます。
%PosixTime データ型形式(エンコードされた 64 ビットの符号付き整数)は、%TimeStamp データ型よりも少ないディスク容量とメモリ使用で済むため、%TimeStamp よりも優れたパフォーマンスが期待されます。%PosixTime でサポートされる最も古い日時は、0001-01-01 00:00:00 で、論理値は -6979664624441081856 です。そして、サポートされる最後の日時は 9999-12-31 23:59:59.999999 で、論理値は 1406323805406846975 です。
現在日時を%PosixTime型で出力したり、%TimeStamp データ型形式にしたい場合は以下のように行えます。
USER>set ptime = ##Class(%Library.PosixTime).CurrentTimeStamp()
USER>write ptime
1154596073773251031
USER>write ##Class(%Library.PosixTime).LogicalToTimeStamp(ptime)
2023-01-24 14:06:06.404055
USER>write ##Class(%Library.PosixTime).TimeStampToLogical("2023-01-24 14:06:06.404055")
1154596073773251031
詳細はクラスリファレンスをご覧ください。%Library.PosixTime
***
Cachéをお使いのお客様は、残念ながら%PosixTime データ型形式は使用できません。「それでも何とか TimeStamp型のクエリのパフォーマンスを向上させたい!」場合は、代替案として新しい計算フィールド(Calculated/SqlComputed)をテーブルに追加し、それらにインデックスを作成する方法があります。
こちらを使用する場合、タイムスタンプを $H 形式の文字列で保存するため、インデックスのデータサイズが小さくなった分だけのパフォーマンスが向上します。
例:以下のような計算プロパティを追加します。
Property DataTS As %TimeStamp;
Property DataTS2 As %String [ Calculated, SqlComputeCode = { Set {*}=$ZDTH({DataTS},3)}, SqlComputed ]; // これを追加
インデックスは、"2022-09-21 11:31:00" の代わりに "66373,41452" で作成するようになります。
この場合、アプリで使用しているクエリ自体も変更する必要があります。日付の比較は以下のように行います。
SELECT *
FROM
TEST.TABLE1
WHERE
tochar(DataTS2, 'YYYY-MM-DD')||' '||tochar(substring(DataTS2,7,5), 'HH24:MI:SS')
BETWEEN
'2000-01-01 00:00:00' and '2022-12-31 23:59:59'
/// $H 日付データを 'YYYY-MM-DD HH24:MI:SS' 形式に変更する
/// tochar(DataTS2, 'YYYY-MM-DD')||' '||tochar(substring(DataTS2,7,5), 'HH24:MI:SS')
【関連】TIMESTAMP型のフォーマットについて日付範囲クエリのSQLパフォーマンスを改善する TIMESTAMP型の項目に対して、TO_CHAR() や TO_DATE() を用いた SELECT を実行するとエラーになります
記事
Mihoko Iijima · 2025年6月25日
これは InterSystems FAQ サイトの記事です。
管理ポータルのシステム管理やシステムエクスプローラーなど最上位のメニューについては、事前定義ロールをユーザに付与することでアクセスを制限することができます。
最下位のメニュー、例えば [システム管理] > [構成] > [システム構成] > [ネームスペース] などは、事前定義ロールの %Manager を付与されたユーザであれば、全てのユーザが利用できてしまいます。
このページに対して、「%Manager ロールを持っているが、あるユーザは使用でき あるユーザは使用できない」のようにユーザ毎のアクセス制限を追加したい場合は、カスタムリソースを作成し再下位メニューに対して作成したカスタムリソースを付与することで制限を追加することができます。
手順は以下の通りです。
カスタムリソースを任意名で作成する。この時パブリック許可は設定しない。
管理ポータルの任意の再下位メニューに 1 で作成したカスタムリソースを設定する。
新規でロールを作成し、1で作成したカスタムリソースに対する USE 許可を設定する。
メニューを利用できるユーザを 3 で作成したロールのメンバーに設定する。
具体的な設定の流れは以下の通りです。
1. カスタムリソースを任意名で作成する。この時パブリック許可は設定しない。
管理ポータル > [システム管理] > [セキュリティ] > [リソース] の画面で新規リソースを作成します。
図例では、Restrict リソースをパブリック許可なしで作成しています。
2、管理ポータルの任意の再下位メニューに 1 で作成したカスタムリソースを設定する。
図では、管理ポータル > [システム管理] > [構成] > [システム構成] > [ネームスペース] の画面に対してアクセス制限を加えたいため、このメニューに 1 で作成したリソースを設定します。
デフォルトの状態は以下の通りです。
リソースを追加した後は以下の通りです。
3、新規でロールを作成し、1で作成したカスタムリソースに対する USE 許可を設定する。
次は、ユーザ毎にアクセスを変えたいため、作成したカスタムリソースの USE 許可を持つロールを作成します。
RestrictedRole ロール作成の流れは以下の通りです。
4、メニューを利用できるユーザを 3 で作成したロールのメンバーに設定する。
予め、TestM1、TestM2 ユーザを作成しそれぞれに %Manager ロールを付与している状態を作っています。
さらに、3 で作成したロールのメンバーに TestM1 ユーザを追加しています。
最後に、設定後の画面表示を確認します。
TestM1 ユーザでログインした場合、[ネームスペース]メニューは利用できますが、TestM2 ユーザは追加設定したカスタムリソースに対する USE 許可を持たないため、メニューにアクセスできないことが確認できました。