[Cloud]Oracle Developer Cloudのビルドパイプラインの一部としてコードマージを行う方法/Code Merge as part of a Build Pipeline in Oracle Developer Cloud

原文はこちら。
https://blogs.oracle.com/developers/code-merge-as-part-of-a-build-pipeline-in-oracle-developer-cloud























この記事ではOracle Developer Cloudでのパイプライン構成の一部として、コードのマージを行う方法を説明します。簡単に使えるビルド・ジョブ機能だけをこれを使って実現することができます。また、開発者が日々の開発作業を行う際に、どのようにこの機能が役立つかについても理解することができるでしょう。

新規Gitリポジトリの作成

ナビゲーションバーのProject Homeをクリックします。Projectページで使用するプロジェクトを選び(例ではDemoProjectを選択しています)、+ Create Repositoryボタンを押すと新規リポジトリが作成されます。この記事では、このリポジトリを使ってcode mergeを行います。
New Repositoryダイアログでは、リポジトリ名を入力します。例ではMyMergeRepoとしていますが、好きな名前を使ってください。Initialize repository with README fileオプションを選び、Createボタンを押しましょう。

新規ブランチの作成

ナビゲーションバーのGitをクリックします。GitページのRefsビューで、RepositoriesドロップダウンからMyMergeRepo.gitを選びます。+ New Branchボタンを押すと新規ブランチが作成されます。
New Branchダイアログでは、一意になるブランチ名を入力します。例ではchangeを使っていますが、好きな名前にしてください。適切なBaseブランチをドロップダウンリストから指定しましょう。例ではmasterブランチのみしか選択肢がありません。Createボタンを押し、新規ブランチを作成しましょう。

ビルドジョブ設定を作成する

ナビゲーションバーからBuildsをクリックします。Jobsタブで、+ Create Jobボタンを押すと、新規ビルドジョブが作成されます。
New Jobダイアログでは、ジョブ名として一意となる名前を指定しましょう。例ではMergeCodeとしていますが、好きな名前を入力してください。Use for Merge Requestチェックボックスにチェックを入れ、Create Newオプションを選択したら、ドロップダウンリストから任意のソフトウェアテンプレートを選んでください。マージを行う際に特に必要となる特定のソフトウェアバンドルなく、いずれのソフトウェアテンプレートにもデフォルトで含まれているソフトウェアバンドルだけで十分です。最後にCreate Jobボタンをクリックしましょう。
注意:VMテンプレートの構成とVMの構築に詳しくない場合、Set Up the Build Systemを参照してください。

Use for Merge Requestにチェックを入れてビルドジョブを作成すると、Source ControlタブのRepositoryBranchフィールドにマージリクエストパラメータが格納されます。そのままAutomatically perform build on SCM commitチェックボックスにチェックを入れましょう。

Build Parametersタブを見ると、GIT_REPO_URLやGIT_REPO_BRANCHなどのマージリクエストパラメータが自動的に追加されていることにお気づきでしょう。確認したら、Saveボタンを押しましょう。

マージリクエストの作成

ナビゲーションバーのMerge Requestsをクリックし、+ Create Merge Requestボタンを押しましょう。
New Merge Requestウィザードでは、Gitリポジトリ(MyMergeRepo)を選択し、ターゲットブランチ(master)とレビューブランチ(change)を選択します。まだ何もコミットしてないので、何も表示されません。Nextボタンをクリックして次のページに進みましょう。
Detailsページでは、Linked BuildフィールドでMergeCodeを選択し、また、レビュアーを設定します。このマージリクエストに紐づけたいissueがある場合は、Linked Issuesフィールドで設定しましょう。Nextボタンをクリックし、最後のページに移動します。
マージリクエストの説明欄のコメントは、デフォルトのものを使うこともできますし、編集することもできます。では、Createボタンを押してマージリクエストを作成しましょう。
Linked Buildsタブでは、MergeCodeビルドジョブがリンクされたビルドジョブとして表示されます。

ファイルを更新し変更をGitリポジトリにコミット

GitページでリポジトリのドロップダウンリストからMyMergeRepo.gitリポジトリを選択し、ブランチのドロップダウンリストからchangeブランチを選択します。そしてREADME.mdファイルのリンクをクリックしましょう。
鉛筆のアイコンをクリックしてファイルを編集します。
任意のテキストを追記し、Commitボタンをクリックします。

コードのコミットによりMergeCodeビルドジョブがトリガーされます。

リンクされたジョブのビルドが起動されると、Conversationタブに自動的にコメントが追加されます。MergeCodeのビルドが完了すると、マージリクエストが自動的に承認され、MergeCode自身がReview StatusリストのApproveセクションに追加され、マージリクエストにアサインされているレビュアーの承認待ちの状態になります。
レビュアーがマージリクエストを承認すると、レビューブランチにあるコードをターゲットブランチにマージできる状態になります。Mergeボタンをクリックすると、コードがマージされます。
注意:この例のマージリクエストではログインしているユーザーであるAlex Adminがレビュアーです。
ビルドジョブにMerge Requestパラメータを含めておくことにより、全てのコミットに対してコンフリクトが発生していないか、承認されているかのチェックを自動的に行うようにすることができます。マージリクエスト用のビルドジョブをリンクしておくと、ひとつのマージリクエストに複数のコミットが紐付られているような場合に有用です。マージリクエストに対してアサインされたレビュアーからのコードレビューと変更の承認が行われたのち、コードがターゲットブランチにマージされます。
日々の開発作業において開発者がチームメンバーと効率的に協働することを手助けしてくれるような機能です。
良いコーディングを!

[Cloud]Joining an Oracle Linux Client to an Active Directory Domain

原文はこちら。

これまでに思い出せないくらい多くの方法でLinuxユーザーアカウントを管理してきましたが、その中で一番良い方法だと思うのはWindowsを少々活用することです。Active Directoryは大規模なコンピューター、ユーザー、そしてグループを簡単に扱えるのと同様に、小規模なそれらを管理するのにも適しています。セットアップも簡単です。

始める前に

Active Directoryをすでにセットアップしてあり、また、そのドメインに参加させたいOracle Linuxが稼働するインスタンスが起動してある必要があります。まだActive Directoryを構成していない場合は、Creating Your Windows Active Directory Domain Servers in Oracle Cloud Infrastructureのホワイトペーパーに記載されている、Oracle Cloud Infrastructure上に素早く、また堅牢にActive Directoryを構成する詳細な方法を参照してください。
インスタンス上で以下の情報を収集します:
変数説明
ip-addressインスタンスのIPアドレス10.0.0.14
hostnameインスタンスの短縮ホストネームunicorn-painter-998
domainインスタンスのドメイン名(また、Active Directory realm)lilwoods.us
fqdnインスタンスのfully qualified domain name (上記IPアドレスに対しての)unicorn-painter-998.lilwoods.us
dns-ip-addressActive DirectoryのIPアドレス10.0.0.13
join-userドメインに参加する権限のあるActive Directoryユーザーmia427
admin-groupsudo権限を付与するActive DirectoryグループUnicorn-Admins

手順
  1. 以降のコマンドは全てスーパーユーザーを必要とするため、root権限に昇格します
    sudo -i
    
  2. /etc/resolv.confファイルを編集し、nameserverとしてActive DirectoryのIPアドレスを使用するようにしましょう。また、他のnameserverレコードは削除しておきます。デフォルトのnameserver (169.254.169.254)を、以下のように変更します。
    nameserver {dns-ip-address}
    例:
    nameserver 10.0.0.14
  3. /etc/hostsファイルの先頭行を以下のように編集し、インスタンスのip-address、fqdnおよびhostnameを記載しておきましょう。
    {ip-address} {fqdn} {hostname}
    
    注意:Oracle Cloud Infrastructureインスタンスでは、インスタンス生成時にインスタンス名からデフォルトのFQDNとhostnameが生成されます。ファイル内にインスタンスのIPアドレスに対して別のレコードが存在していないことを確かめてください。
    例:
    10.0.0.14 unicorn-painter-998.lilwoods.us unicorn-painter-998
    
  4. Acrive Directoryに接続するために使われているrealmdツールとその依存パッケージをインストールしましょう。
    yum -y install realmd sssd krb5-workstation krb5-lids samba-common-tools
  5. Active Directory realm (また、DNS domainでもあります)をdiscoverしましょう。
    realm discover ${DOMAIN}
    
    例:
    realm discover lilwoods.us
    
  6. Active Directory realmにjoinしましょう。
    realm join --verbose ${REALM} -U ${JOIN_USER}
    
    例:
    realm join --verbose lilwoods.us -U mia427@lilwoods.us
    
    プロンプトが出るので、adminパスワードを入力してください。
    Linuxサーバーが管理ドメインへの参加に成功すると、以下のようなメッセージが表示されます。
    Successfully enrolled machine in realm
    
  7. sudoersファイルを編集し、Adminsグループのメンバーにsudo権限を付与しましょう。
    visudo
    
    wheelグループがあるファイルの半分ほどのところまで移動し、このグループの下にActive Directoryグループ名をsudoers設定ファイルに追記しておきましょう。将来参照するときのために説明も追記しておきます。
    # Allow users in the admin group to run all commands
    {REALM}\\{AD-Group-Name} ALL=(ALL) ALL
    
    例:
    # Allow users in the Unicorn-Admins group to run all commands     
    %LILWOODS.US\\Unicorn-Admins ALL=(ALL) ALL
  8. /etc/ssh/sshd_configファイルを編集し、Active Directoryからの認証情報を受け入れるためにSSHサービス内でのパスワード認証を許可しておきましょう。PasswordAuthentication noPasswordAuthentication yesに変更します。
  9. 設定変更を適用するため、sshdを再起動します。
    systemctl restart sshd
    
これで完了です!インスタンスは以下の設定になりました:
  • Active Directoryに登録済
  • Active Directory内のユーザーがSSHログインアクセス可能
  • 新規ログイン時、ホームディレクトリスケルトンが生成される
  • Active Directoryのあるグループに所属するユーザーは、sudoアクセスが可能
  • このインスタンスからのKerberos認証が可能

[Cloud, Functions] Serverless Image Classification with Oracle Functions and TensorFlow

原文はこちら。
https://blogs.oracle.com/cloud-infrastructure/serverless-image-classification-with-oracle-functions-and-tensorflow

画像分類は、機械学習技術の実証でよく使われます。このエントリでは、最近発表されたクラウドサービスのOracle FunctionsでTensorFlowベースの画像分類アプリケーションを実行する方法をご紹介します。
TensorFlow
https://www.tensorflow.org/
Announcing Oracle Functions
https://blogs.oracle.com/cloud-infrastructure/announcing-oracle-functions
https://orablogs-jp.blogspot.com/2018/12/announcing-oracle-functions.html

Oracle Functions

Oracle Functionsはフルマネージドで高い拡張性を備える、オンデマンドのFunction as a Serviceプラットフォームで、エンタープライズクラスのOracle Cloud Infrastructure上に構築されています。
Oracle Cloud Infrastructure
https://cloud.oracle.com/ja_JP/cloud-infrastructure
基盤となるインフラストラクチャを気にせずにビジネスニーズを満たすコードを書くことに集中でき、実行中に消費されるリソースに対してのみ課金される、サーバーレス製品です。コードをデプロイして直接またはトリガーに応じて呼び出すことができ、アプリケーションの高可用性、スケーラビリティ、安全かつ監視対象とするために必要な、背後のすべての作業はOracle Functionsが担います。

Oracle Functionsはオープンソース、コンテナネイティブ、任意の環境、つまりクラウドまたはオンプレミスで実行できるサーバーレスのプラットフォームであるFn Projectをベースにしています。
Fn Project
http://fnproject.io/
Fn Projectのオープンソースディストリビューションをダウンロード、インストールし、functionをローカルで開発およびテストしてから、同じツールを使用してそのfunctionをOracle Functionsにデプロイできます。

What to Expect

詳細に入る前に、サーバーレス機械学習関数から期待できるものを見ていきましょう。セットアップして動作させると、アプリケーションを画像にポイントし、画像がどのようなものかを想定し、そしてその想定の確からしさをあわせて返します。

例えば、分類関数に渡した場合、以下の画像では次のように返します。
This is a ‘pizza’ Accuracy—100%

Photo by Alan Hardman on Unsplash

The Code

イメージ分類関数は既存のTensorFlowのサンプルをベースにしています。
Image Classification Example
https://github.com/tensorflow/models/tree/master/samples/languages/java/label_image
この関数はTensorFlow Java SDKを使っていて、この中ではJNI(Java Native Interface)を介してネイティブC++実装を利用しています。
Install TensorFlow for Java
https://www.tensorflow.org/install/lang_java

Function Image Input

画像分類関数はFn Java FDKを利用しており、このおかげでJavaでのfunctionの開発および実行プロセスがシンプルになります。

Java JDKを使う利点の1つは、functionに送られた入力をJavaのオブジェクトと型にシームレスに変換できることです。これには以下のものが含まれます。
Java API and runtime for fn
https://github.com/fnproject/fdk-java/
  • 文字列入力処理のようなシンプルなデータバインディング
  • JSONデータ型をPOJOにバインド。Jacksonを使って内部で実装しているため、カスタマイズ可能。
    Main Portal page for the Jackson project
    https://github.com/FasterXML/jackson
  • functionが受信もしくは返す生のFn Java FDKイベントの抽象化によって、生の入力を操作可能。
入力データと出力データのマーシャリング方法をカスタマイズしたい場合は、バインディングをさらに拡張できます。
Extending the Data Binding functionality
https://github.com/fnproject/fdk-java/blob/master/docs/ExtendingDataBinding.md
既存のTensorFlowのサンプルでは、入力として画像名のリスト(コード実行マシンに画像が存在する必要があります)を想定しています。この関数も同様に動作しますが、Fn Java FDKがもたらす柔軟なバインディング機能を使用している点が重要な違いです。classifyメソッドはfunctionのエントリポイントとして機能し、functionに渡されるイメージのraw byteを表すJavaバイト配列(byte[])を受け入れます。このバイト配列は、staticなTensor.create(byte[])メソッドを使ってTensorオブジェクトを作成するために利用されます。
Tensor
https://www.tensorflow.org/api_docs/java/reference/org/tensorflow/Tensor
public static Tensor<String> create (byte[])
https://www.tensorflow.org/api_docs/java/reference/org/tensorflow/Tensors#create(byte%5B%5D)
public class LabelImageFunction {
 public String classify(byte[] image) {
 ...
 Tensor<String> input = Tensors.create(image);
 ...
  }
}
完全なソースコードはGitHubからご覧いただけます。
Serverless image classification with functions & TensorFlow
https://github.com/abhirockzz/fn-hello-tensorflow

Machine Learning Model

通常、機械学習ベースのシステムは以下のフェーズで構成されています。
  • Training(学習):アルゴリズムに過去のデータ(履歴データ)を食わせて学習(パターンを導出)させ、モデルを構築する。多くの場合このプロセスは継続して実行される。
  • Predicting(予測):生成されたモデルを使い、学習フェーズで学んだ事実に基づき、新たな入力に対応する予測や出力を生成する。
このアプリケーションでは事前学習済みのモデルを使います。さらに便利なことに、分類ロジックが必要とするこのモデル(およびラベル)はfunctionそのもの(Dockerイメージの一部)と共にパッケージされています。これらはソースコードのresourcesフォルダにあります。

このことは、TensorFlow Servingのような専用のモデル提供コンポーネントを設定する必要がない、ということです。
TensorFlow Serving for model deployment in production
https://www.tensorflow.org/serving/

Function Metadata

func.yaml ファイルには、メモリ割り当てやタイムアウトのような属性値(このfunctionではそれぞれ1024MB、120秒が設定されています)を含む、functionのメタデータが記述されています。このメタデータは、(より単純な計算とは対照的に)画像分類アルゴリズムの(かなり)厳しい性質のために必要な値になっています。
schema_version: 20180708
name: classify
version: 0.0.1
runtime: java
memory: 1024
timeout: 120
triggers:
- name: classify
  type: http
  source: /classify
以下は設定している属性のサマリです。
  • schema_version:このファイルが従う仕様のバージョン
  • name:このfunctionをプッシュする際の名前とタグ
  • version:functionの現在のバージョン。デプロイ時にタグとしてイメージに追加する。
  • runtime:プログラミング言語ランタイム。この例ではJava。
  • memory (optional) :このfunctionの最大メモリ閾値。このfunctionが実行時にこの上限を超えると、functionは停止し、エラーメッセージをログ出力する。
  • timeout (optional) :function実行の最大許容時間
  • triggers (optional) :functionのトリガーを指定するためのトリガー・エンティティの配列。この例では、HTTPトリガーを使用。

Function Dockerfile

Oracle Functionsは、ビルドおよび実行時フェーズで一連の事前ビルド済みかつ言語固有のDockerイメージを使います。例えばJava functionの場合、fn-java-fdk-buildをビルドフェーズで利用し、実行時にはfn-java-fdkを使います。
fn-java-fdk-build
https://hub.docker.com/r/fnproject/fn-java-fdk-build/
fn-java-fdk
https://hub.docker.com/r/fnproject/fn-java-fdk/
以下はfunction用のDockerイメージ作成で使うデフォルトのDockerfileです。
FROM fnproject/fn-java-fdk-build:jdk9-1.0.75 as build-stage
WORKDIR /function
ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository
ADD pom.xml /function/pom.xml
RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"]
ADD src /function/src
RUN ["mvn", "package"]
FROM fnproject/fn-java-fdk:jdk9-1.0.75
WORKDIR /function
COPY --from=build-stage /function/target/*.jar /function/app/
CMD ["com.example.fn.HelloFunction::handleRequest"]
このDockerfileはマルチステージDockerビルドを使って(標準で)以下のアクションを実行します。
  • maven package およびmaven build
  • (COPYコマンドを使って)functionのJARファイルと依存関係をランタイムイメージにコピー
  • functionのコンテナが生成されたら、(CMDコマンドを使って)実行コマンドを設定
しかし、例えば3rdパーティのネイティブライブラリを組み込むために、Dockerイメージの作成をさらに制御する必要がある場合があるでしょう。そのような場合は、カスタムDockerfileを使いたいと思うでしょう。あなたのfunctionのレシピを定義する自由を手に入れるため、非常に強力です。やるべきことは、基本のDockerイメージ拡張する、これだけです。
Docker base images for various programming languages
https://github.com/fnproject/dockers
以下はこのfunctionで利用しているDockerfileです。
FROM fnproject/fn-java-fdk-build:jdk9-1.0.75 as build-stage
WORKDIR /function
ENV MAVEN_OPTS -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort= -Dhttp.nonProxyHosts= -Dmaven.repo.local=/usr/share/maven/ref/repository
ADD pom.xml /function/pom.xml
RUN ["mvn", "package", "dependency:copy-dependencies", "-DincludeScope=runtime", "-DskipTests=true", "-Dmdep.prependGroupId=true", "-DoutputDirectory=target", "--fail-never"]'
ARG TENSORFLOW_VERSION=1.12.0
RUN echo "using tensorflow version " $TENSORFLOW_VERSION
RUN curl -LJO https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-$TENSORFLOW_VERSION.jar
RUN curl -LJO https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow_jni-cpu-linux-x86_64-$TENSORFLOW_VERSION.tar.gz
RUN tar -xvzf libtensorflow_jni-cpu-linux-x86_64-$TENSORFLOW_VERSION.tar.gz
ADD src /function/src
RUN ["mvn", "package"]
FROM fnproject/fn-java-fdk:jdk9-1.0.75
ARG TENSORFLOW_VERSION=1.12.0
WORKDIR /function
COPY --from=build-stage /function/libtensorflow_jni.so /function/runtime/lib
COPY --from=build-stage /function/libtensorflow_framework.so /function/runtime/lib
COPY --from=build-stage /function/libtensorflow-$TENSORFLOW_VERSION.jar /function/app/
COPY --from=build-stage /function/target/*.jar /function/app/
CMD ["com.example.fn.LabelImageFunction::classify"]
maven buildのようなデフォルトのステップに加え、組み込んでいる追加のカスタマイズに着目してください。
  • (指示に従って)TensorFlowのセットアップを自動化し、TensorFlow Java SDKとネイティブJNI(.so)ライブラリを展開
    Install TensorFlow for Java
    https://www.tensorflow.org/install/lang_java
  • (Docker buildの第2段階の一部として)JNIライブラリーを/function/runtime/libにコピーし、SDK JARを/function/appにコピーして、実行時にこのfunctionで使用できるようにする

Deploying to Oracle Functions

先述の通り、オープンソースのFn CLIを使ってOracle Functionsをデプロイできます。最新バージョンであることを確認してください。
CLI tool for fnproject
https://github.com/fnproject/cli/
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
​以下のURLから直接ダウンロードすることもできます。
fnproject/cli - Releases
https://github.com/fnproject/cli/releases

Oracle Functions Context

Oracle Functionsを使用する前に、Oracle Cloud Infrastructureテナントに接続するようにFn Project CLIを構成する必要があります。

Fn Project CLIを最初にインストールすると、ローカル開発コンテキスト用に設定されます。そうではなく、Fn Project CLIをOracle Cloud Infrastructureテナントに接続するように設定するには、新しいコンテキストを作成する必要があります。コンテキスト情報は~/.fn/contextディレクトリ内の.yamlファイルに格納されます。このファイル内で、Oracle Functionsのエンドポイント、デプロイされた機能が属するコンパートメントのOCID、Oracle Cloud Infrastructureの構成ファイル、およびイメージのプッシュ先およびプル元のDockerレジストリのアドレスを指定します。

以下はコンテキストファイルの例です。
api-url: https://functions.us-phoenix-1.oraclecloud.com
oracle.compartment-id: <OCI_compartment_OCID>
oracle.profile: <profile_name_in_OCI_config>
provider: oracle
registry: <OCI_docker_registry> 

Oracle Cloud Infrastructure Configuration

Oracle Cloud Infrastructureの構成ファイルには、ユーザーの資格証明とテナントのOCIDが含まれています。
SDK and CLI Configuration File
https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdkconfig.htm
これらのエントリに対して異なる値を持つ複数のプロファイルを作成できます。そのため、oracle.profile属性を使ってCLIが利用するプロファイルを定義できます。

以下は構成ファイルの例です。
[DEFAULT]
user=ocid1.user.oc1..exampleuniqueID
fingerprint=20:3b:97:13:55:1c:5b:0d:d3:37:d8:50:4e:c5:3a:34
key_file=~/.oci/oci_api_key.pem
tenancy=ocid1.tenancy.oc1..exampleuniqueID
pass_phrase=tops3cr3t
region=us-ashburn-1
[ORACLE_FUNCTIONS_USER]
user=ocid1.user.oc1..exampleuniqueID
fingerprint=72:00:22:7f:d3:8b:47:a4:58:05:b8:95:84:31:dd:0e
key_file=/.oci/admin_key.pem
tenancy=ocid1.tenancy.oc1..exampleuniqueID
pass_phrase=s3cr3t
region=us-phoenix-1
複数のコンテキストを定義でき、それぞれは異なるコンテキストファイルに保存されます。Functions開発環境に従って、正しいコンテキストに切り替えてください。
fn use context <context_name>

Create the Application

GitHubリポジトリのコンテンツをクローンするところから始めます。
git clone https://github.com/abhirockzz/fn-hello-tensorflow
以下はアプリケーションデプロイ時に必要なコマンドです。
fn create app <app_name> --annotation oracle.com/oci/subnetIds='["<subnet_ocid>"]'
  • <app_name>:新たなアプリケーションの名前
  • <subnet_ocid> :functionを実行するサブネットのOCID
以下は例です。
fn create app fn-tensorflow-app --annotation oracle.com/oci/subnetIds='["ocid1.subnet.oc1.phx.exampleuniqueID","ocid1.subnet.oc1.phx.exampleuniqueID","ocid1.subnet.oc1.phx.exampleuniqueID"]'

Deploy the Function

アプリケーション作成後、以下のコマンドでfunctionをデプロイできます。
fn deploy --app <app_name>
<app_name>はfunctionを追加するOracle Functionsのアプリケーションの名前です。

(Java SDKと対応するネイティブライブラリで)TensorFlow v 1.12.0を使いたい場合、以下のコマンドを使います。
fn -v deploy --app fn-tensorflow-app
特定のバージョンを選択することもできます。その場合は、functionのビルド前にpom.xmlファイルで指定することをお忘れなく。例えば、v 1.11.0を使いたい場合、以下のように設定してください。
<dependency>
 <groupId>org.tensorflow</groupId>
 <artifactId>tensorflow</artifactId>
 <version>1.11.0</version>
 <scope>provided</scope>
</dependency>
Tofunctionのデプロイ時にバージョンを指定したい場合、以下のように--build-arg(ビルド引数)を使います。
fn -v deploy --app fn-tensorflow-app --build-arg TENSORFLOW_VERSION=<version>
例えばv1.11.0を使う場合は以下のようです。
fn -v deploy --app fn-tensorflow-app --build-arg TENSORFLOW_VERSION=1.11.0
デプロイが無事に成功すると、functionは利用可能になっています。fn ls appsコマンドを使って現在デプロイされているアプリケーションをリスト表示すると、n-tensorflow-appが出てくるはずです。

Time to Classify Images!

前述の通り、このfunctionは入力として画像を受け取り、それが何であるかを正確さのパーセンテージと共に伝えます。

推奨された画像のいくつかをダウンロードして試すか、もしくはすでにコンピュータにある画像を使うことができます。呼び出し時にfunctionにイメージを渡すだけでOKです。
download_sample_images.sh
https://github.com/tensorflow/models/blob/master/samples/languages/java/label_image/download_sample_images.sh
cat <path to image> | fn invoke fn-tensorflow-app classify
はい、では試してみましょう。この画像でソンブレロを検出できますか?
cat /Users/abhishek/manwithhat.jpg | fn invoke fn-tensorflow-app classify

“366 • 9 • Gringo” (CC BY-NC-ND 2.0) by Pragmagraphr

結果
This is a ‘sombrero’ Accuracy — 92%
テリアはどうでしょうか。
cat /Users/abhishek/terrier.jpg | fn invoke fn-tensorflow-app classify

“Terrier” (CC BY-NC 2.0) by No_Water

結果
This is a 'West Highland white terrier' Accuracy - 88%
次は何を分類しましょうか?

Summary

シンプルでありながらも完全に機能する機械学習アプリケーションをクラウドにデプロイしました。試してみたいですよね?

Oracle Functionsは2019年に一般提供の予定ですが、現在Cloud Native Limited Availability Programを通じて選ばれたお客様に対してのみご利用いただけるようにしております。Oracle Functionsの詳細ならびにOracle Functionsへのアクセスのリクエストは、こちらから登録をお願いします。Oracle Functionsで使われている、基礎のオープンソーステクノロジーの詳細は、FnProject.ioをご覧ください。
FnProject
http://fnproject.io/

[misc.] Logico v1 is terminated and Logico Mk-Ⅱ is GA

江草家を長らくご愛顧いただきありがとうございます。

ロジ子のステルス性低下が顕著という課題に対処することを目的に江草家で家族会議をした結果、グレードアップが必要との結論にいたり、その結果、ロジ子はv1からMk-Ⅱに生まれ変わることになりました。
  • ブログは引き続きこちらを使いますが、将来移行する可能性があります。その際にはお知らせします。
  • 情報発信のためのTwitterアカウントはLogico Mk-Ⅱ (LogicoMk2)に変わります。
    Logico_jpは今後も継続しますが、江草家からの情報発信目的から離れます。
2011/01/19からおよそ8年間、どうもありがとうございました。今後、どこかでみなさまとお目にかかれる日がありましたら、「ロジ子発見!」とTwitterに書き込んでやってください(その前にステルス性を復活させるので、見つからないようにしますけどねw)。
今後はLogico Mk-Ⅱが皆様に色々情報をお伝えしてまいります。
今後ともどうぞよろしくお願いいたします。

江草ロジ子
Logico Mk-Ⅱ

[Cloud] Automated Generation For OCI IAM Policies

原文はこちら。
https://blogs.oracle.com/developers/automated-generation-for-oci-iam-policies

OracleのCloud Developer Evangelistとして、Oracle CloudのサービスやOracle Cloudの提供機能で遊ぶことがよくあります。これはもちろんOCI (Oracle Cloud Infrastructure) Compute ConsoleのIdentity and Access Management (IAM) のセクションでかなり色々やっているということなのですけどね。
Overview of Oracle Cloud Infrastructure Identity and Access Management
https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/overview.htm
IAMは非常に簡単なコンセプトで、他のクラウドベンダーのIAMを使ったことがあればご存知のことでしょう。IAMについては既に十分に説明されており、ドキュメントが簡潔でわかりやすいので、ここでは完全な概要を説明しませんが、想定より時間がかかってしまうタスクが、IAMポリシーの生成です。
Getting Started with Policies
https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/policygetstarted.htm
OCIのIAMポリシーの構文は以下の通りです。
Allow <subject> to <verb> <resource-type> in <location> where <conditions>
構文自体はかなり簡単そうですね。そして実際にそうなのですが、よくある問題は、ポリシーの変数セクションに入れる値を覚えていなければならない、ということです。正確なグループ名、または使用可能な動詞とリソースタイプ、およびポリシーを適用したいコンパートメントの正確な名前を覚えておくのは面倒で、通常は2つまたは3つのタブを開いて正確な綴り、大文字/小文字を調べ、正しい動詞とリソースの種類を知るためにドキュメントをめくっています。そんなわけで、ポリシー生成にあたってもう少し楽にするために何かしようと決めました。そして、この問題に他にも苦しんでいる人がいらっしゃるのであればその方々に共有したいと考えました。

そこで、私のフラストレーションと怠惰から生まれた、OCIのIAMポリシー生成を支援する簡単なプロジェクトをご紹介します。このツールをコマンドラインから実行すると、各変数を選択するように求められます。あなたのOCIアカウントからの実際の値に基づいて利用可能な選択肢を選択できます。例えば、特定のグループを対象にしたポリシーの作成を選択した場合、このツールは選択可能なグループのリストを提示します。ツールには動詞やリソースタイプのリストが組み込まれているので、同様に選択することができます。毎回IAMポリシードキュメントを参照する必要はありません。以下はツールを実行中のイメージです。

コード自体は傑作ではありません。OCI CLIまたはSDKを介して公開されていないため、動詞やリソースタイプはハードコードされているからです。しかしながら動作し、ポリシー生成が少々楽になっています。ツール生成のコードはGitHubにありますので、ツールのアップデートや機能強化目的でプルリクエストを送ってください。
A simple Groovy tool to generate IAM policies for Oracle Cloud Infrastructure.
https://github.com/recursivecodes/oci-policy-generator
ツールはGroovyで書いているので、Groovyスクリプトまたはjava -jarを使って実行できます。もしバイナリを手に入れて試してみたいのであれば、最新のリリースを入手して試してみてください。
oci-policy-generator - releases
https://github.com/recursivecodes/oci-policy-generator/releases
このツールは、裏でOCI CLIを使用しており、必要に応じてOCI APIを照会しています。ポリシーを生成する前に、OCI CLIがマシンにインストールおよび設定されていることを確認しておく必要があります。
Command Line Interface (CLI)
https://docs.cloud.oracle.com/iaas/Content/API/Concepts/cliconcepts.htm
外部の依存関係を最小限に抑え、プロジェクトをできるだけ軽量に保ちながら価値を提供するために、SDKではなくCLIを使用することにしました。それに、OCI CLIは非常に素晴らしいものなので、Oracle Cloudを使用する場合は、間違いなくそれをインストールし、それに精通している必要があります。

是非ツールをチェックいただき、何か質問やフィードバックがありましたらいつも通り(原文の)コメント欄にコメントをお願いします。

[Cloud, Java] Controlling Your Cloud - Uploading Large Files To Oracle Object Storage

原文はこちら。
https://blogs.oracle.com/developers/controlling-your-cloud-uploading-large-files-to-oracle-object-storage

前回のエントリでは、OCI Java SDKでOracle Cloud Infrastructure(OCI)APIを操作する概要を説明しました。
Controlling Your Cloud - A Look At The Oracle Cloud Infrastructure Java SDK
http://blogs.oracle.com/developers/controlling-your-cloud-a-look-at-the-oracle-cloud-infrastructure-java-sdk
https://orablogs-jp.blogspot.com/2019/01/controlling-your-cloud-look-at-oracle.html
エントリ中で、SDKを掘り下げようとしたのは、OCI Object Storageへの大容量ファイルのアップロードを処理するためであると述べました。このエントリでは、実際にマルチパート・アップロードをやってみます。

先に述べたように、HTTP(Hypertext Transfer Protocol)はもともと大きなファイル転送を扱うことを意図しておらず、ファイル転送は通常(そして多くの場合、依然として)FTP(File Transfer Protocol)を使って処理されていました。しかし、Web開発者はグローバルに分散されたクライアントを扱っており、FTPはサーバーのセットアップ、カスタムデスクトップクライアント、さまざまなファイアウォールルール、および認証を必要とするため、最終的に大きなファイルをHTTP/Sを使って転送してしまうのです。状況が許せば、Bit Torrentがより良い解決策になるかもしれませんが、Web開発者が扱っている分散ファイルはほとんどの場合解決策にはなりません。過去数年にわたるHTTPの多くの進歩のおかげで、大きなファイル転送が扱いやすくなりました。主な進歩は、(「チャンク」または「マルチパート」ファイルアップロードとして知られる)Chunked Transfer Encodingです。
Chunked Transfer Encoding
https://en.wikipedia.org/wiki/Chunked_transfer_encoding
マルチパートアップロードに関する Oracleのサポートについては、以下のドキュメントで詳細を説明していますが、できる限り簡単に説明するとすれば、ファイルをいくつかの部分(「チャンク」)に分割し、(必要に応じて同時に)アップロードし、すべての部分がアップロードされたら元のファイルに再構築するというものです。
Using Multipart Uploads
https://docs.cloud.oracle.com/iaas/Content/Object/Tasks/usingmultipartuploads.htm
Java SDKを使ってマルチパートアップロードを実施するには、少なくとも3ステップ必要です。詳細を期したSDKのJavaDocsは以下からご覧いただけます。
Oracle Cloud Infrastructure Java SDK - 1.3.3
https://docs.cloud.oracle.com/iaas/tools/java/latest/
  1. Initiate the multipart upload
  2. Upload the individual file parts
  3. Commit the upload
SDKは上記手順の全てのためのメソッドだけでなく、既存のマルチパートアップロードのリストなどのための追加の手順のためのメソッドも提供しています。個々のファイルは最大50GBになる可能性があります。上記の3つのステップを完了するために必要なObjectClient(前の記事を参照)を使用するSDKプロセスを以下のように説明しています。
1. CreateMultipartUploadRequestDetailsインスタンスを含むCreateMultipartUploadRequestインスタンスを渡してObjectClient.createMultipartUploadを呼び出す。
ステップ1を詳説すると、「ファイルをアップロードしたい。オブジェクト名はfoo.jpg、コンテンツタイプはimage / jpegだ。後でそのファイルの異なるピースを関連付けられるよう、識別子を教えてくれるかな?」とAPIに尋ねれば、APIはCreateMultipartUploadResponseの形で識別子を返してくれる、ということです。以下がそのコード例です。
// route handler (Bootstrap.groovy):
post "/oci/upload-create", { req, res ->
    def objectName = req.queryParams("objectName")
    def contentType = req.queryParams("contentType")
    return JsonOutput.toJson( objectService.createMultipartUpload(objectName, contentType) )
}

// service method (ObjectService.groovy):
def createMultipartUpload(objectName, contentType="application/octet-stream") {
    CreateMultipartUploadDetails createMultipartUploadDetails = CreateMultipartUploadDetails.builder()
            .object(objectName)
            .contentType(contentType)
            .build()
    CreateMultipartUploadRequest createMultipartUploadRequest = CreateMultipartUploadRequest.builder()
            .namespaceName(namespaceName)
            .bucketName(bucketName)
            .createMultipartUploadDetails(createMultipartUploadDetails)
            .build()
    return objectClient.createMultipartUpload(createMultipartUploadRequest)
}
ではアップロードを作成するために、objectNameとcontentTypeという引数を渡して、/oci/upload-createを呼び出します。Postmanを使って呼び出していますが、これはブラウザでfetch()を呼び出すのと同じくらい簡単です。

これで今後の作業のためのアップロード識別子を取得しました(上図の2のuploadIdをご覧ください)。ではプロセスの2番目の手順に入ります。
2. uploadId、objectName、各パーツ用の連番(partNum)、チャンクされたファイルを含むUploadPartRequestのインスタンスを付けてObjectClient.uploadPart()を呼び出し、UploadPartResponseを受け取る。このレスポンスには、この後アップロードを完了するためにパーツの連番と共に保存しておくべきETagが含まれている。
以下は手順2のコード例です。
//route handler (Bootstrap.groovy):
post "/oci/upload-part", { req, res ->
    req.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement("/tmp"))
    HttpRequestWrapper reqRaw = req.raw()
    InputStream is = reqRaw.getPart("uploadPart").getInputStream()
    def objectName = req.queryParams("objectName")
    def partNum = req.queryParams("partNum").toInteger()
    def uploadId = req.queryParams("uploadId")
    return JsonOutput.toJson( objectService.uploadPart(is, objectName, uploadId, partNum) )
}

//service method (ObjectService.groovy):
def uploadPart(InputStream inputStream, String objectName, String uploadId, int partNum) {
    UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
            .namespaceName(namespaceName)
            .bucketName(bucketName)
            .objectName(objectName)
            .uploadPartBody(inputStream)
            .uploadId(uploadId)
            .uploadPartNum(partNum)
            .build()
    return objectClient.uploadPart(uploadPartRequest)
}
これがPostmanのステップ2の呼び出しです。アップロードはファイルの各パートに対して1回実行されました。最後の手順で使用するため、ETag値を各パーツの連番(partNum)と共に保存します。


最後の手順3でアップロードが完了します。
3. objectName、uploadId、そしてCommitMultipartUploadPartDetailsの配列を含むCommitMultipartUploadDetailsインスタンスを含むCommitMultipartUploadRequestインスタンスを渡して、ObjectClient.commitMultipartUpload()を呼び出す。
ややこしそうに見えますが、そnSounds a bit complicated, but it's really not.  The code tells the story here:
//route handler (Bootstrap.groovy):
post "/oci/upload-commit", { req, res ->
    /*
    expects a JSON object in the request body that looks like this:
    {
        uploadId: "",
        objectName: "",
        uploads: [
            {
                partNum: 1,
                ETag: "",
            }
        ]
    }
    */
    Map body = new JsonSlurper().parseText(req.body())
    def details = []
    body.uploads.each { Map file ->
        details << CommitMultipartUploadPartDetails.builder()
                .partNum(file.partNum)
                .etag(file.ETag)
                .build()

    }

    return JsonOutput.toJson( objectService.commitMultipartUpload(body.objectName, body.uploadId, details) )
}

//service method (ObjectService.groovy):
def commitMultipartUpload(String objectName, String uploadId, List partDetails) {
    CommitMultipartUploadDetails commitMultipartUploadDetails = CommitMultipartUploadDetails.builder().partsToCommit(partDetails).build()
    CommitMultipartUploadRequest commitMultipartUploadRequest = CommitMultipartUploadRequest.builder()
            .namespaceName(namespaceName)
            .bucketName(bucketName)
            .objectName(objectName)
            .uploadId(uploadId)
            .commitMultipartUploadDetails(commitMultipartUploadDetails)
            .build()
    return objectClient.commitMultipartUpload(commitMultipartUploadRequest)
}
呼び出すと、マルチパート・アップロードのコミットの完了を確認するシンプルなレスポンスが返ってきます。Object Storageのバケットに移動すると、アップロードされ再構築されたファイルの詳細を確認できます。



そして、私たちがあらかじめ決められたURLで当該URL(もしくはバケットが公開されていれば直接)アクセスすれば、その画像を見ることができます。今回の場合は、ペットのMosesの写真です。



説明した通り、マルチパート・アップロード用のOracle SDKは、必要な手順に分類されていればかなり簡単に利用できます。適切なバックエンドサービスを利用できるのであれば、マルチパートアップロードを支援するためのフロントエンドライブラリが多数あります(今回は、MacBookのsplitコマンドを使って単純に分割しました)。

[Java, Support] Oracle Java SE Releases FAQ

原文はこちら。
https://blogs.oracle.com/java-platform-group/oracle-java-se-releases-faq

Q1: Is Java still free after January 2019?(2019年1月以後もJavaは無料ですか?)

もちろんです。 20年以上に渡ってそうであったように、OracleはJavaを無料でオープンに保ち、安定性、パフォーマンス、およびセキュリティのアップデートを現在のバージョンに無料で提供しています。またOracleは新しいリリースサイクルの下で、事前に1年前に予定した無料のcritical patch updates(CPU)、必要に応じて追加アップデート、ならびに2回のfeature updates(critical patch updatesも含む)を毎年提供し続けます。
Critical Patch Updates, Security Alerts and Bulletins
https://www.oracle.com/technetwork/topics/security/alerts-086861.html
Critical Patch UpdatesとSecurity Alerts
https://www.oracle.com/technetwork/jp/topics/alerts-082677-ja.html
Update and FAQ on the Java SE Release Cadence
https://blogs.oracle.com/java-platform-group/update-and-faq-on-the-java-se-release-cadence
https://orablogs-jp.blogspot.com/2018/05/update-and-faq-on-java-se-release.html
Oracleはこのすべての開発をOpenJDKオープンソース・コミュニティーで行っており、私たちの貢献はオープンソースとして誰にでも移植、分析、使用できるようになっています。jdk.java.netからオープンソースライセンスの下で、OracleからのJavaの最新アップデート(Oracle OpenJDKバイナリ)をダウンロードできます。そして開発およびテスト目的でOTNからOracle JDKをダウンロードできます。
Java Development Kit builds, from Oracle
http://jdk.java.net/
Java SE Downloads - Oracle Technology Network
https://www.oracle.com/technetwork/java/javase/downloads/index.html

Q2: What does “End of Public Updates” mean?(パブリックアップデートの終了とはどういうことですか?)

5年間のパブリックに利用可能な期間を経て、Java 8は2019年初頭にパブリックアップデートの終了を迎えます。これはJava 5(2009年)、Java 6(2013年)、Java 7(2015年)と同様です。
End of Public Updates is a Process, not an Event
https://blogs.oracle.com/java-platform-group/end-of-public-updates-is-a-process%2c-not-an-event
https://orablogs-jp.blogspot.com/2018/09/end-of-public-updates-is-process-not.html
Oracleは、jdk.java.netおよびOTNで、現在のリリースに対する安定性、パフォーマンス、およびセキュリティのアップデートを含む、予測可能で事前にスケジュール済みの無料のアップデートを提供します。以前のリリースは、公開されているスケジュールに従って、My Oracle Supportを通じてOracleのお客様は引き続き利用可能で、サポートされます。
My Oracle Support
https://support.oracle.com/
Oracle Java SE Support Roadmap
https://www.oracle.com/technetwork/java/java-se-support-roadmap.html(英語)
https://www.oracle.com/technetwork/jp/java/eol-135779-ja.html(日本語)

Q3: What does "free for personal use" mean?(個人利用は無料とはどういうことですか?)

以前の「パブリックアップデートの終了」(Java 5は2009年、Java 6は2013年、Java 7は2015年)は、すべての種類のユーザーに対して、同時に決まった日に行われました。
昨年発表したように、OracleはJava 8のパブリックアップデートの終了を2018年9月から2019年1月に延長しました。
Extension of Oracle Java SE 8 Public Updates and Java Web Start support
https://blogs.oracle.com/java-platform-group/extension-of-oracle-java-se-8-public-updates-and-java-web-start-support
https://orablogs-jp.blogspot.com/2018/01/extension-of-oracle-java-se-8-public.html
Oracleはさらに個人利用や、個人のデスクトップやラップトップで利用する場合はJava 8の無料のパブリックアップデート期間を少なくとも2020年末まで延長しました。これにより、未だにレガシーなJava 8 applet、Web Start、JavaFX機能(これらはJava 9もしくはそれ以後のバージョンで削除されました)を使っている可能性があるB2Cタイプのアプリケーションを使う個人向けに無料のアップデートが提供されます。この件に関する詳細情報は昨年公開済みです。
The Future of JavaFX and Other Java Client Roadmap Updates
https://blogs.oracle.com/java-platform-group/the-future-of-javafx-and-other-java-client-roadmap-updates
https://orablogs-jp.blogspot.com/2018/03/the-future-of-javafx-and-other-java.html
つまり、個人のデスクトップコンピュータまたはラップトップコンピュータにて、ゲームやパーソナルバンキング、その他の個人消費者向けのアクティビティのためにJava 8に必要とする人は、少なくとも2020年まで無料のアップデートを入手できる、ということです。

商用ユーザーは、Oracleから無料で入手できる新しいJavaバージョンにアップデートできます。また、Java 8などの古いバージョンの利用が重要な場合は、Java SE Subscriptionを検討してください。
Oracle Java SE Subscriptions
https://www.oracle.com/java/java-se-subscription.html
https://www.oracle.com/jp/java/java-se-subscription.html

Q4: What are the Java 8 “End of Public Updates” timelines?(Java 8のパブリックアップデート終了のタイムラインとは?)

2019年1月15日(US時間)に予定されているJava 8向けのCritical Patch Update(8u201とそれに関連するPatch Set Updateの8u202)が、BCLライセンスの下で入手可能な最後のアップデートです。このBCLライセンスは一般的な目的のデスクトップやサーバー利用向けには一般に無料で、数年間にわたるOracle JDKのライセンスでした。
Critical Patch Updates, Security Alerts and Bulletins
https://www.oracle.com/technetwork/topics/security/alerts-086861.html
Critical Patch UpdatesとSecurity Alerts
https://www.oracle.com/technetwork/jp/topics/alerts-082677-ja.html
Java CPU and PSU Releases Explained
https://www.oracle.com/technetwork/java/javase/cpu-psu-explained-2331472.html
Oracle Binary Code License Agreement for the Java SE Platform Products and JavaFX
https://java.com/license
2019年4月16日に予定されている、次回のJava 8のアップデート(8u211および関連するPatch Set Updateの8u212)は新たなライセンスの下で利用可能になります。このライセンスは個人のデスクトップ利用、開発やテスト、プロトタイピングやデモ目的では無料になる予定です。

最新のJavaリリースは、オープンソースライセンスの下でjdk.java.netから無償ダウンロード可能なもの、または開発、テスト、プロトタイピングおよびデモンストレーション目的であればOTNから無償ダウンロード可能なものがあります。Java SE Subscriptionsは、2019年4月16日に入手可能なJava 8のアップデートを商用または本番用に引き続き使用したいという方がご利用いただけます。Java SE Subscription FAQには、価格設定などの追加情報があります。
Oracle Java SE Subscription FAQ
https://www.oracle.com/technetwork/java/javaseproducts/overview/javasesubscriptionfaq-4891443.html(英語)
https://www.oracle.com/technetwork/jp/java/javaseproducts/overview/javasesubscriptionfaq-4891443-ja.html(日本語)

Q5: Can an update of Java 8, released before April 2019, and downloaded under the BCL, continue to be used after January 2019?(2019年4月より前のJava 8のアップデートはBCLの下でダウンロードでき、2019年1月以後も引き続き利用できますか?)

はい。 提供されたライセンス条項の下で、任意のバージョンのJavaを継続して利用できます。Java 8アップデートの新規ライセンスは、2019年1月より後の新しいライセンスに基づいてリリースされたアップデートに対してのみ適用されます。これは2019年4月16日に予定されている四半期アップデート以後が該当します。

以前のJavaのパブリックアップデート(Java 1.1にまでさかのぼることができます)はJava Archivesから入手できます。
Oracle Java Archive
https://www.oracle.com/technetwork/java/archive-139210.html
これらの旧バージョンは古いシステムでの問題をデバッグする開発者を支援することを目的として提供しており、最新のセキュリティパッチでアップデートされていませんので、本番運用での利用には推奨いたしません。

Q6: I’m an Oracle Customer with an Oracle product that uses Java. Can you confirm Java updates and support is included for use with that Oracle product?(Javaを使うOracle製品を利用しているOracleの顧客ですが、当該Oracle製品と共に利用する目的でJavaのアップデートおよびサポートが含まれているのでしょうか?)

はい。Java SEを必要とする、サポート対象のOracle製品をご利用のOracleのお客様であれば、サポート対象のOracle製品利用のために、Oracle製品が必要とするOracle Javaのアップデートに引き続きアクセスできます。その際に追加コストはかかりません。詳細はMy Oracle Supportの以下のサポートドキュメントをご覧ください(サポート契約ならびにログインが必要です)。
Support Entitlement for Java SE When Used As Part of Another Oracle Product (Doc ID 1557737.1)
https://support.oracle.com/rs?type=doc&id=1557737.1
サポートノート : 他の Oracle 製品の一部として Java SE を利用する場合の Java SE サポートについて (Doc ID 1612709.1)
https://support.oracle.com/rs?type=doc&id=1612709.1

Q7: Why does the Java Auto Update recommend removing unused versions of Java?(Java Auto UpdateがJavaの未使用バージョンを削除するよう推奨するのはなぜ?)



Javaのアップデートにあたっては、システムをきれいに保つために、アップデート完了後に古いバージョンを削除することを日常的に推奨しています。

2019年1月から、Java Auto Updateで、6か月以上コンピュータでJavaを使用していないかどうかも検出し、使用していない場合はJavaを更新するのではなく削除するよう提案する場合があります。Oracle eDeliveryまたはMy Oracle SupportからJavaをインストールしたお客様に対しては、これらのメッセージを表示しません。誤ってJavaをアンインストールし、後で必要になったと判断した場合は、java.com/downloadを参照するか、Oracleのカスタマサポートおよび提供チャネルを通じていつでも再インストールできます。
Free Java Download
https://www.java.com/download/

Q8: What if I’m an ISV?(ISVの場合はどうなの?)

上記のFAQの質問に対する回答は、ISVおよび内部利用のためにJavaを使用しているユーザーに適用されます。ソフトウェアの実行に使用するJavaのバージョンをユーザーに選択させる必要があるISVは、Oracleから無料で提供される最新のJavaバージョン(Oracle OpenJDKバイナリ)と、Java SE Subscriptionを通じて入手可能な旧バージョンのOracle Javaの両方をサポートするアプローチに従うことができます。アプリケーションにJavaを組み込んでいるISVは、jdk.java.netから利用可能な無料のオープンソースリリースを選択、もしくは、JDKアップデートの提供のためにOracleにコンタクトできます。
Oracle Contacts
https://www.oracle.com/corporate/contact/

Q9: What other resources are available?(利用可能なリソースはありますか?)

[Cloud, Java] Controlling Your Cloud - A Look At The Oracle Cloud Infrastructure Java SDK

原文はこちら。
https://blogs.oracle.com/developers/controlling-your-cloud-a-look-at-the-oracle-cloud-infrastructure-java-sdk

数週間前、クラウドエバンジェリズムチームは、3日間のクラウドhackfestを行い、カリフォルニア州サンタクララの弊社のお客様企業から3名のすばらしい開発者が参加されました。このイベントの間、開発者の一人が、自身のチームが直面している課題は、非常に大きいサイズになる可能性のあるファイルのアップロード処理であると述べました。私も以前、開発者としてこの問題に直面しており、確かに困難ではあります。(後で説明するように、ここ数年で状況は大幅に改善されましたが)Webは大きなサイズのファイルを転送するために作られたものではありません。hackfest期間中にこの問題に完全に対処するまでには至りませんでしたが、帰宅後Oracle Cloud Infrastructure APIを深く掘り下げ、引き続き解決策を探すことを開発者に約束しました。それで昨日、私はプロセスを掘り下げることにし、その開発者のためにOCI Object Storageに大きなファイルをアップロードする方法についてかなりしっかりとしたデモを設計しました。しかしそのソリューションを説明する前に、内容が高度になっても追随できるよう、入手可能なSDKを使ったOracle Cloudの操作の基本を紹介いたします。

Oracleは他にもいくつかの言語(Python、Ruby、Go)のSDKを提供していますが、通常Groovyを使ってコードを書くので、Java SDKを使いました。
Software Development Kits and Command Line Interface
https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdks.htm
Java SDK
https://docs.cloud.oracle.com/iaas/Content/API/SDKDocs/javasdk.htm
Oracleはクラウド操作のための完全なREST APIを提供していますが、SDKでは素敵なネイティブソリューションを提供し、リクエストを署名し、HTTP呼び出しをアプリケーション内にバンドルできる素敵なパッケージにするという面倒な部分を抽象化してくれます。 Java SDKは以下のOCIサービスをサポートします。
  • Audit
  • Container Engine for Kubernetes
  • Core Services (Networking, Compute, Block Volume)
  • Database
  • DNS
  • Email Delivery
  • File Storage
  • IAM
  • Load Balancing
  • Object Storage
  • Search
  • Key Management
実際にJava SDK、特にObject Storageサービスとやり取りするためのJava SDKの使用方法を見てみましょう。SDKはオープンソースでGitHubから利用できます。
Java SDK for Oracle Cloud Infrastructure
https://github.com/oracle/oci-java-sdk
このデモ用に非常にシンプルなWebアプリを作成しましたが、残念ながら、まだMavenからSDKを入手できませんので、まず第一にSDKをダウンロードして、それをアプリケーションの依存関係として含める必要がありました。
Maven release
https://github.com/oracle/oci-java-sdk/issues/25
oci-java-sdk library
https://github.com/oracle/oci-java-sdk/releases
Gradleを使っているので、アプリケーションのルート直下にあるlibsディレクトリにJARを配置し、以下の依存関係ブロックを宣言してGradleが確実にローカルJARを拾うようにしました(重要なのは、8行目の "implementation"メソッドです) .

dependencies {
    localGroovyConf localGroovy()
    compile 'org.codehaus.groovy:groovy-all:2.5.4'
    compile 'com.sparkjava:spark-core:2.7.2'
    compile 'org.slf4j:slf4j-simple:1.7.21'
    compile group: 'org.apache.tika', name: 'tika-core', version: '1.19.1'
    
    implementation fileTree(dir: 'libs', include: ['*.jar'])
}
次は、認証およびサービス呼び出しに必要なシステムプロパティの作成です。このために、ローカルに構成ファイルを設定し、キーペアを生成する必要があります。これは最初は面倒ではありますが、一度設定すれば将来設定する必要がありません。後で使いたい場合、OCI CLI用の設定もすでに済んでいるというメリットもあります。
SDK and CLI Configuration File
https://docs.cloud.oracle.com/iaas/Content/API/Concepts/sdkconfig.htm
構成ファイルとキーを生成したら、プロパティをアプリケーションのルートにあるgradle.propertiesに書き出します。このプロパティファイルと以下に示すキーの命名規則を使用すれば、Gradleで変数をシステムスクリプトとしてビルドスクリプト内で使用できます。
ビルドスクリプト内でシステムプロパティとして変数を使用しても、それらをアプリケーション内で使用できるわけではありません。利用できるようにするため、'run'タスクを介してシンプルに変数を渡すことができます。
task runServer(dependsOn: 'classes', type: JavaExec) {
    System.setProperty('environment', 'prod')
    dependsOn 'classes'
    classpath = sourceSets.main.runtimeClasspath
    main = 'codes.recursive.Bootstrap'
    systemProperties = System.getProperties()
}
続いて、プロバイダーとサービスクライアントを管理するためのクラスを作成しました。このクラスには現在1個のクライアントしかありませんが、将来簡単に他のサービス用にクライアントを追加できます。
package codes.recursive.service

import com.oracle.bmc.auth.AuthenticationDetailsProvider
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider
import com.oracle.bmc.objectstorage.ObjectStorage
import com.oracle.bmc.objectstorage.ObjectStorageClient

import java.security.Security

class OciClientManager {

    AuthenticationDetailsProvider provider

    OciClientManager(configFilePath=System.getProperty("ociConfigPath"), profile=System.getProperty("ociProfile")) {
        this.provider =  new ConfigFileAuthenticationDetailsProvider(configFilePath, profile)
        // per https://docs.cloud.oracle.com/iaas/Content/API/SDKDocs/javasdkconfig.htm#JavaVirtualMachineTTLforDNSNameLookups
        Security.setProperty("networkaddress.cache.ttl" , "60")
    }

    ObjectStorage getObjectClient(region=System.getProperty("ociObjectStorageRegion")) {
        ObjectStorage client = new ObjectStorageClient(this.provider)
        client.setRegion(region)
        return client
    }
}
続いて、Object Storage APIを操作するための'ObjectService'を作成しました。コンストラクタが上記のOciClientManagerインスタンスを受け入れ、コンストラクタは上で見たOciClientManagerのインスタンスを受け取り、多くのSDKメソッドに共通するもの(名前空間、バケット名、コンパートメントIDなど)用のクラス変数を設定します。
OciClientManager clientManager
ObjectStorage objectClient
String bucketName = "doggos"
String namespaceName

ObjectService(OciClientManager clientManager) {
    this.clientManager = clientManager
    this.objectClient = clientManager.getObjectClient()
    GetNamespaceResponse namespaceResponse = objectClient.getNamespace(
            GetNamespaceRequest.builder().build()
    )
    this.namespaceName = namespaceResponse.getValue()
}
これでSDKと対話する準備が整いました。 開発者の立場としては、それは間違いなく直感的なAPIといってよいでしょうし、他のクラウドプロバイダが自身のクラウドAPIでも使用する標準的なリクエスト/レスポンスモデルに従っています。何が次のメソッドやプロパティを呼ぶのかを単純に推測して、それが正しい(もしくはIntelliSenseが適切な場所をガイドしてくれる)ことが多かったわけですが、これは優れたAPIのためのベンチマークといってよいでしょう。ただし、直感的で肥大化した認証方式で邪魔をしないのであれば、ですが。誤解しないで頂きたいのは、強力な認証とセキュリティは確かに重要ですが、SDKの目的は複雑さを隠し、APIを簡単な方法で使用するためのメソッドを公開することです。それはさておき、Object Storageクライアントの使い方を見てみましょう。

では早速、クライアントを使って以下のアクションを実行する方法を示します(各コードブロックの後に結果の例を付けています)。
  1. List Buckets
  2. Get A Bucket
  3. List Objects In A Bucket
  4. Get An Object
List Buckets:
def listBuckets() {
    ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder()
            .namespaceName(this.namespaceName)
            .compartmentId(System.getProperty("ociCompartmentId"))
            .build()
    ListBucketsResponse listBucketsResponse = objectClient.listBuckets(listBucketsRequest)
    return listBucketsResponse
}


Get Bucket:
def getBucket() {
    def listBucketsResponse = listBuckets()
    GetBucketRequest getBucketRequest = GetBucketRequest.builder()
            .namespaceName(this.namespaceName)
            .bucketName( listBucketsResponse.items.find { it.name == this.bucketName }.name )
            .fields([GetBucketRequest.Fields.ApproximateCount])
            .build()
    GetBucketResponse getBucketResponse = objectClient.getBucket(getBucketRequest)
    return getBucketResponse
}


List Objects:
def listObjects() {
    ListObjectsRequest listObjectsRequest = ListObjectsRequest.builder()
            .namespaceName(this.namespaceName)
            .bucketName(this.bucketName)
            .build()
    ListObjectsResponse listObjectsResponse = objectClient.listObjects(listObjectsRequest)
    return listObjectsResponse
}


Get Object:
def getObject() {
    def listObjectsResponse = listObjects()
    GetObjectRequest getObjectRequest = GetObjectRequest.builder()
            .namespaceName(namespaceName)
            .bucketName(bucketName)
            .objectName(listObjectsResponse.listObjects.objects.first().name)
            .build()
    GetObjectResponse getObjectResponse = objectClient.getObject(getObjectRequest)
    def object = Util.writeInputStream(getObjectResponse.inputStream, getObjectResponse.contentType)
    return [object: object, response: getObjectResponse]
}


'Get Object'の例には、ファイルへ書き込み可能なオブジェクトを含むInputStreamも含まれています。

ご覧のとおり、Object Storage APIは予測可能で一貫性があります。別のエントリでは、SDKを使った大規模ファイルのアップロード処理に関する、より複雑な問題に取り組みます。