    001package org.opengion.fukurou.model;
    002
    003import java.io.ByteArrayInputStream;
    004import java.io.ByteArrayOutputStream;
    005import java.io.File;
    006import java.io.FileFilter;
    007import java.io.FileNotFoundException;
    008import java.io.IOException;
    009import java.io.InputStream;
    010import java.net.URI;
    011import java.util.ArrayList;
    012import java.util.List;
    013
    014import org.opengion.fukurou.util.Closer;
    015import org.opengion.fukurou.util.StringUtil;
    016
    017/**
    018 * クラウドストレージ対応用の抽象クラスです。
    019 * 各ベンダーのストレージに対応したプラグインを作成する場合はこのクラスを継承してください。
    020 *
    021 *
    022 * @og.group ファイル操作
    023 *
    024 * @og.rev 5.10.8.0 (2019/02/01) 新規作成
    025 * @og.rev 5.10.9.0 (2019/03/01) 変更対応
    026 * @author oota
    027 * @since JDK7.0
    028 */
    029public abstract class CloudFileOperation extends FileOperation {
    030
    031        /* クラス定数 */
    032        private static final int BUFFER_SIZE = 1024 * 4;
    033        /* クラス変数 */
    034        // パス
    035        protected final String conPath;
    036        // バケット名
    037        protected final String conBucket;
    038
    039        private final String UNIMPLEMNTED_ERR="このクラスでは未実装のメソッドです。";
    040
    041        /**
    042         * コンストラクタ
    043         *
    044         *
    045         * @param bucket バケット名
    046         * @param inPath ファイルパス
    047         */
    048        public CloudFileOperation(final String bucket, final String inPath) {
    049                super(inPath);
    050
    051                this.conPath = editPath(replaceFileSeparetor(inPath));
    052
    053                this.conBucket = bucket;
    054
    055                if (StringUtil.isNull(conBucket)) {
    056                        String errMsg = "バケット未指定です。hayabusa利用ではシステム変数の「CLOUD_BUCKET」にバケット名を設定して下さい。";
    057                        throw new RuntimeException(errMsg);
    058                }
    059        }
    060
    061        /**
    062         * データ書き込み
    063         *
    064         * InputStreamのデータを書き込みます。
    065         *
    066         * @param is 書き込みデータのInputStream
    067         * @throws IOException IO関連のエラー情報
    068         */
    069        @Override
    070        public abstract void write(InputStream is) throws IOException;
    071
    072        /**
    073         * データ読み込み
    074         *
    075         * データを読み込み、InputStreamを返します。
    076         *
    077         * @return 読み込みデータのInputStream
    078         * @throws FileNotFoundException ファイル非存在エラー情報
    079         */
    080        @Override
    081        public abstract InputStream read() throws FileNotFoundException;
    082
    083        /**
    084         * ファイル削除
    085         *
    086         * ファイルを削除します。
    087         *
    088         * @return 成否フラグ
    089         */
    090        @Override
    091        public abstract boolean delete();
    092
    093        /**
    094         * ファイルコピー
    095         *
    096         * ファイルを指定先にコピーします。
    097         *
    098         * @param afPath コピー先
    099         * @return 成否フラグ
    100         */
    101        @Override
    102        public abstract boolean copy(String afPath);
    103
    104        /**
    105         * ファイルサイズ取得
    106         *
    107         * ファイルサイズを返します。
    108         *
    109         * @return ファイルサイズ
    110         */
    111        @Override
    112        public abstract long length();
    113
    114        /**
    115         * 最終更新時刻取得
    116         *
    117         * 最終更新時刻を返します。
    118         *
    119         * @return 最終更新時刻
    120         */
    121        @Override
    122        public abstract long lastModified();
    123
    124        /**
    125         * ファイル判定
    126         *
    127         * ファイルの場合は、trueを返します。
    128         *
    129         * @return ファイルフラグ
    130         */
    131        @Override
    132        public abstract boolean isFile();
    133
    134        /**
    135         * ディレクトリ判定
    136         *
    137         * ディレクトリの場合は、trueを返します。
    138         *
    139         * @return ディレクトリフラグ
    140         */
    141        @Override
    142        public abstract boolean isDirectory();
    143
    144        /**
    145         * 一覧取得
    146         *
    147         * パスのファイルと、ディレクトリ一覧を取得します。
    148         *
    149         * @return ファイルとティレクトリ一覧
    150         */
    151        public abstract File[] listFiles(FileFilter filter);
    152
    153        /**
    154         * 親ディレクトリの取得
    155         *
    156         * 親のディレクトリ情報を返します。
    157         *
    158         * @return 親のディレクトリ
    159         */
    160        @Override
    161        public abstract File getParentFile();
    162
    163        /**
    164         * ファイルパス取得
    165         *
    166         * ファイルパスを取得します。
    167         *
    168         * @return 設定パス
    169         */
    170        @Override
    171        public String getPath() {
    172                return conPath;
    173        }
    174
    175        /**
    176         * 絶対パス取得
    177         *
    178         * 絶対パスを取得します。
    179         *
    180         * @return 絶対パス
    181         */
    182        @Override
    183        public String getAbsolutePath() {
    184                return conPath;
    185        }
    186
    187        /**
    188         * ファイル名取得
    189         *
    190         * ファイル名を取得します。
    191         *
    192         * @return 名称
    193         */
    194        @Override
    195        public String getName() {
    196                return drawName(conPath);
    197        }
    198
    199        /**
    200         * 親のパス取得
    201         *
    202         * 親のパスを取得します。
    203         *
    204         * @return 親のパス
    205         */
    206        @Override
    207        public String getParent() {
    208                return drawParent(conPath);
    209        }
    210
    211        /**
    212         * ファイル移動
    213         *
    214         * ファイルを指定先に移動します。
    215         *
    216         * @param afPath 移動先
    217         * @return 成否フラグ
    218         */
    219        @Override
    220        public boolean move(String afPath) {
    221                boolean flgRtn = false;
    222
    223                flgRtn = copy(afPath);
    224                if (flgRtn) {
    225                        flgRtn = delete();
    226                }
    227
    228                return flgRtn;
    229        }
    230
    231        /**
    232         * 存在チェック
    233         *
    234         * 存在する場合は、trueを返します。
    235         *
    236         * @return 存在フラグ
    237         */
    238        @Override
    239        public boolean exists() {
    240                return isDirectory() | isFile();
    241        }
    242
    243        /**
    244         * ディレクトリの作成
    245         *
    246         * ※１つのディレクトリのみ作成します。
    247         * クラウドストレージにはディレクトリの概念が無いため、
    248         * 作成は行わず、trueを返します。
    249         *
    250         * @return 成否フラグ
    251         */
    252        @Override
    253        public boolean mkdir() {
    254                return true;
    255        }
    256
    257        /**
    258         * ディレクトリの作成(複数)
    259         *
    260         * ※複数のディレクトリを作成します。
    261         * クラウドストレージにはディレクトリの概念が無いため、
    262         * 作成は行わず、trueを返します。
    263         *
    264         *
    265         * @return 成否フラグ
    266         */
    267        @Override
    268        public boolean mkdirs() {
    269                return true;
    270        }
    271
    272        /**
    273         * ファイル名変更
    274         *
    275         * 指定のファイル情報のファイル名に変更します。
    276         *
    277         * @param dest 変更後のファイル情報
    278         * @return 成否フラグ
    279         */
    280        @Override
    281        public boolean renameTo(File dest) {
    282                return move(dest.getPath());
    283        }
    284
    285        /**
    286         * 書き込み可能フラグ
    287         *
    288         * ※クラウドストレージの場合は、
    289         * 存在すればtrueを返します。
    290         *
    291         * @return 書き込み可能フラグ
    292         */
    293        @Override
    294        public boolean canWrite() {
    295                return exists();
    296        }
    297
    298        /**
    299         * 読み取り可能フラグ
    300         *
    301         * ※クラウドストレージの場合は、
    302         * 存在すればtrueを返します。
    303         *
    304         * @return 読み取り可能フラグ
    305         */
    306        @Override
    307        public boolean canRead() {
    308                return exists();
    309        }
    310
    311        /**
    312         * 隠しファイルフラグ
    313         *
    314         * ※クラウドストレージの場合は、
    315         * 必ずfalseを返します。
    316         *
    317         * @return 隠しファイルフラグ
    318         */
    319        @Override
    320        public boolean isHidden() {
    321                return false;
    322        }
    323
    324        /**
    325         * 新規ファイル作成
    326         *
    327         * 既にファイルが存在しない場合のみ、
    328         * 空のファイルを作成します。
    329         *
    330         * @return 成否フラグ
    331         * @throws IOException ファイル関連エラー情報
    332         */
    333        @Override
    334        public boolean createNewFile() throws IOException {
    335                boolean rtn = false;
    336
    337                if (!exists()) {
    338                        InputStream is = null;
    339                        try {
    340                                is = new ByteArrayInputStream(new byte[0]);
    341                                write(is);
    342                                rtn = true;
    343                        } finally {
    344                                Closer.ioClose(is);
    345                        }
    346                }
    347
    348                return rtn;
    349        }
    350
    351        /**
    352         * 最終更新時刻の更新
    353         *
    354         * 最終更新時刻の更新を行います。
    355         * ※クラウドストレージの場合は、
    356         * 最終更新時刻の更新を行えません。
    357         *
    358         * @param time 更新する最終更新時刻
    359         * @return 成否フラグ
    360         */
    361        @Override
    362        public boolean setLastModified(long time) {
    363                // クラウドストレージでは、setLastModifiedによる、
    364                // 最終更新時刻の設定はできないので、
    365                // 処理を行わずにtrueを返します。
    366                return true;
    367        }
    368
    369        /**
    370         * カノニカルファイル情報の取得
    371         *
    372         * ※ローカルサーバのみ通常ファイルと、
    373         * カノニカルファイルで異なります。
    374         *
    375         * @return カノニカルファイル情報
    376         * @throws IOException ファイル関連エラー情報
    377         */
    378        @Override
    379        public FileOperation getCanonicalFile() throws IOException {
    380                return this;
    381        }
    382
    383        /**
    384         * toString
    385         *
    386         * パスを返します。
    387         *
    388         * @return ファイルパス
    389         */
    390        @Override
    391        public String toString() {
    392                return conPath;
    393        }
    394
    395        /** 共通関数 **/
    396        /**
    397         * ファイルパスの編集
    398         *
    399         * パスの先頭が「/」の場合は「/」の除去と、「//」を「/」に置換処理の追加。
    400         *
    401         * @param path ファイルパス
    402         * @return 変更後パス
    403         */
    404        protected String editPath(final String path) {
    405                if (StringUtil.isNull(path)) {
    406                        return "";
    407                }
    408                String rtn = path;
    409
    410                // 「//+」は「/」に置換
    411                rtn = rtn.replaceAll("//+", "/");
    412                // 先頭が「/」の場合は除去
    413                if ("/".equals(rtn.substring(0, 1))) {
    414                        rtn = rtn.substring(1);
    415                }
    416                // 後尾の「.」は除去
    417                rtn = rTrim(rtn, '.');
    418                // 後尾の「/」は除去
    419                rtn = rTrim(rtn, '/');
    420
    421                return rtn;
    422        }
    423
    424        /**
    425         * 親のパスを抽出
    426         *
    427         * キーから親のパスを抽出します。
    428         *
    429         * @param key キー
    430         * @return 親のパス
    431         */
    432        protected String drawParent(String key) {
    433                int k = key.lastIndexOf("/");
    434
    435                String rtn = "";
    436                if (k > 0) {
    437                        rtn = key.substring(0, key.lastIndexOf("/"));
    438                }
    439                if ("/".equals(File.separator)) {
    440                        rtn = File.separator + rtn;
    441                }
    442
    443                return rtn;
    444        }
    445
    446        /**
    447         * 名称の抽出
    448         *
    449         * 引数のkeyから名称を抽出します。
    450         *
    451         * @param key キー(パス)
    452         * @return 名称
    453         */
    454        protected String drawName(String key) {
    455                int k = key.lastIndexOf("/");
    456
    457                String rtn = key;
    458                if (k > 0) {
    459                        rtn = key.substring(key.lastIndexOf("/") + 1);
    460                }
    461                return rtn;
    462        }
    463
    464        /**
    465         * ディレクトリ用のパス編集
    466         *
    467         * 後尾に「/」がない場合は、付与します。
    468         *
    469         * @param path パス
    470         * @return 後尾に「/」ありのパス
    471         */
    472        protected String setDirTail(String path) {
    473                if (StringUtil.isNull(path)) {
    474                        return path;
    475                }
    476
    477                StringBuilder sb = new StringBuilder(path);
    478                if (!"/".equals(path.substring(path.length() - 1))) {
    479                        sb.append("/");
    480                }
    481                return sb.toString();
    482        }
    483
    484        /**
    485         * 右側トリム処理
    486         *
    487         * 右側の文字が、指定の文字の場合、除去します。
    488         *
    489         * @param str 対象文字列
    490         * @param chr 指定文字
    491         * @return 右側から指定文字を除去後の文字列
    492         */
    493        protected String rTrim(final String str, char chr) {
    494                String rtn = str;
    495                int trgPos = 0;
    496                for (int i = str.length() - 1; i >= 0; i--) {
    497                        if (str.charAt(i) == chr) {
    498                                trgPos = i;
    499                                // すべて合致した場合は、から文字を返す
    500                                if (trgPos == 0) {
    501                                        rtn = "";
    502                                }
    503                        } else {
    504                                break;
    505                        }
    506                }
    507
    508                if (trgPos > 0) {
    509                        rtn = str.substring(0, trgPos);
    510                }
    511
    512                return rtn;
    513        }
    514
    515        /**
    516         * ファイル区切り文字変換
    517         *
    518         * ファイル区切り文字を変換します。
    519         *
    520         * @param path 変換前文字列
    521         * @return 返還後文字列
    522         */
    523        protected String replaceFileSeparetor(final String path) {
    524                if (StringUtil.isNull(path)) {
    525                        return "";
    526                }
    527
    528                return path.replaceAll("\\\\", "/");
    529        }
    530
    531        /**
    532         * フィルター処理
    533         *
    534         * フィルター処理を行います。
    535         *
    536         * @param list フィルタを行うリスト
    537         * @param filter フィルタ情報
    538         * @return フィルタ後のリスト
    539         */
    540        protected File[] filter(List<File> list, FileFilter filter) {
    541                List<File> files = new ArrayList<File>();
    542                for (File file : list) {
    543                        if (filter.accept(file)) {
    544                                files.add(file);
    545                        }
    546                }
    547                return files.toArray(new File[files.size()]);
    548        }
    549
    550        /**
    551         * ストリームの変換処理
    552         *
    553         * InputStreamをbyte[]に変換。
    554         * InputStreamのサイズ計算に利用。
    555         *
    556         * @param is byte[]変換するInputStream
    557         * @return InpusStreamをbyte[]に変換した値
    558         * @throws IOException ファイル関連エラー情報
    559         */
    560        protected byte[] toByteArray(InputStream is) throws IOException {
    561                ByteArrayOutputStream output = new ByteArrayOutputStream();
    562                try {
    563                        byte[] b = new byte[BUFFER_SIZE];
    564                        int n = 0;
    565                        while ((n = is.read(b)) != -1) {
    566                                output.write(b, 0, n);
    567                        }
    568                        return output.toByteArray();
    569                } finally {
    570                        output.close();
    571                }
    572        }
    573
    574        /**
    575         * ローカル実行フラグ判定
    576         *
    577         * このabstract クラスの継承クラスはクラウド上で実行されるため、
    578         * falseを返します。
    579         *
    580         * @return ローカル実行フラグ
    581         */
    582        @Override
    583        public boolean isLocal() {
    584                return false;
    585        }
    586
    587        /** java.io.Fileに実装されており、クラウド用ファイルクラスに未実装のメソッドの対応 */
    588        /**
    589         * canExecuteの実行
    590         *
    591         * クラウド側では未実装のメソッドです。
    592         *
    593         * @return フラグ
    594         */
    595        @Override
    596        public boolean canExecute() {
    597                throw new RuntimeException(UNIMPLEMNTED_ERR);
    598        }
    599
    600        /**
    601         * deleteOnExitの実行
    602         *
    603         * クラウド側では未実装のメソッドです。
    604         *
    605         */
    606        @Override
    607        public void deleteOnExit() {
    608                throw new RuntimeException(UNIMPLEMNTED_ERR);
    609        }
    610
    611        /**
    612         * getAbsoluteFileの実行
    613         *
    614         * クラウド側では未実装のメソッドです。
    615         *
    616         * @return File
    617         */
    618        @Override
    619        public File getAbsoluteFile() {
    620                throw new RuntimeException(UNIMPLEMNTED_ERR);
    621        }
    622
    623        /**
    624         * getFreeSpaceの実行
    625         *
    626         * クラウド側では未実装のメソッドです。
    627         *
    628         * @return 数値
    629         */
    630        @Override
    631        public long getFreeSpace() {
    632                throw new RuntimeException(UNIMPLEMNTED_ERR);
    633        }
    634
    635        /**
    636         * getTotalSpaceの実行
    637         *
    638         * クラウド側では未実装のメソッドです。
    639         *
    640         * @return 数値
    641         */
    642        @Override
    643        public long getTotalSpace() {
    644                throw new RuntimeException(UNIMPLEMNTED_ERR);
    645        }
    646
    647        /**
    648         * getUsableSpaceの実行
    649         *
    650         * クラウド側では未実装のメソッドです。
    651         *
    652         * @return 数値
    653         */
    654        @Override
    655        public long getUsableSpace() {
    656                throw new RuntimeException(UNIMPLEMNTED_ERR);
    657        }
    658
    659        /**
    660         * isAbsoluteの実行
    661         *
    662         * クラウド側では未実装のメソッドです。
    663         *
    664         * @return フラグ
    665         */
    666        @Override
    667        public boolean isAbsolute() {
    668                throw new RuntimeException(UNIMPLEMNTED_ERR);
    669        }
    670
    671        /**
    672         * setReadableの実行
    673         *
    674         * クラウド側では未実装のメソッドです。
    675         *
    676         * @param readable フラグ
    677         * @return フラグ
    678         */
    679        @Override
    680        public boolean setReadable(boolean readable) {
    681                throw new RuntimeException(UNIMPLEMNTED_ERR);
    682        }
    683
    684        /**
    685         * setReadableの実行
    686         *
    687         * クラウド側では未実装のメソッドです。
    688         *
    689         * @param readable フラグ
    690         * @param ownerOnly フラグ
    691         * @return フラグ
    692         */
    693        @Override
    694        public boolean setReadable(boolean readable, boolean ownerOnly) {
    695                throw new RuntimeException(UNIMPLEMNTED_ERR);
    696        }
    697
    698        /**
    699         * setWritableの実行
    700         *
    701         * クラウド側では未実装のメソッドです。
    702         *
    703         * @param writable フラグ
    704         * @return フラグ
    705         */
    706        @Override
    707        public boolean setWritable(boolean writable) {
    708                throw new RuntimeException(UNIMPLEMNTED_ERR);
    709        }
    710
    711        /**
    712         * canExecuteの実行
    713         *
    714         * クラウド側では未実装のメソッドです。
    715         *
    716         * @param writable フラグ
    717         * @param ownerOnly フラグ
    718         * @return フラグ
    719         */
    720        @Override
    721        public boolean setWritable(boolean writable, boolean ownerOnly) {
    722                throw new RuntimeException(UNIMPLEMNTED_ERR);
    723        }
    724
    725        /**
    726         * canExecuteの実行
    727         *
    728         * クラウド側では未実装のメソッドです。
    729         *
    730         * @return URI情報
    731         */
    732        @Override
    733        public URI toURI() {
    734                throw new RuntimeException(UNIMPLEMNTED_ERR);
    735        }
    736}