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