    001package org.opengion.fukurou.model;
    002
    003import java.io.ByteArrayInputStream;
    004import java.io.ByteArrayOutputStream;
    005import java.io.File;
    006import java.io.FileNotFoundException;
    007import java.io.IOException;
    008import java.io.InputStream;
    009import java.util.ArrayList;
    010import java.util.List;
    011
    012import org.opengion.fukurou.util.Closer;
    013import org.opengion.fukurou.util.HybsFileFilter;
    014import org.opengion.fukurou.util.StringUtil;
    015
    016/**
    017 * ファイル操作の抽象クラス
    018 *
    019 * 共通の処理等を実装しています。
    020 *
    021 * @og.group ファイル操作
    022 *
    023 * @og.rev 5.10.8.0 (2019/02/01) 新規作成
    024 * @og.auth oota
    025 * @since JDK7.0
    026 */
    027public abstract class AbstractFileOperation implements FileOperation {
    028
    029        /* クラス定数 */
    030        private static final int BUFFER_SIZE = 1024 * 4;
    031        /* クラス変数 */
    032        // パス
    033        protected final String path;
    034        // バケット名
    035        protected final String bucket;
    036
    037        /**
    038         * コンストラクタ
    039         * ローカルサーバ用
    040         */
    041        public AbstractFileOperation() {
    042                path = "";
    043                bucket = "";
    044        }
    045
    046        /**
    047         * コンストラクタ
    048         * クラウドストレージ用
    049         *
    050         * @param buket バケット
    051         * @param inPath パス
    052         */
    053        public AbstractFileOperation(final String buket , final String inPath) {
    054                path = editPath(replaceFileSeparetor(inPath));
    055                this.bucket = buket;
    056
    057                if (StringUtil.isNull(bucket)) {
    058                        String errMsg = "バケット未指定です。hayabusa利用ではシステム変数の「CLOUD_BUCKET」にバケット名を設定して下さい。";
    059                        throw new RuntimeException(errMsg);
    060                }
    061        }
    062
    063        /**
    064         * InputStreamのデータを書き込みます。
    065         *
    066         * @param is 書き込みデータのInputStream
    067         * @throws IOException
    068         */
    069        @Override
    070        public void write(InputStream is) throws IOException {
    071                String errMsg = "このクラスでは実装されていません。write(InputStream is)";
    072                throw new UnsupportedOperationException(errMsg);
    073        }
    074
    075        /**
    076         * データを読み込み、InputStreamとして、返します。
    077         *
    078         * @return 読み込みデータのInputStream
    079         * @throws FileNotFoundException
    080         */
    081        @Override
    082        public InputStream read() throws FileNotFoundException {
    083                String errMsg = "このクラスでは実装されていません。read()";
    084                throw new UnsupportedOperationException(errMsg);
    085        }
    086
    087        /**
    088         * ファイルを削除します。
    089         *
    090         * @return 成否フラグ
    091         */
    092        @Override
    093        public boolean delete() {
    094                String errMsg = "このクラスでは実装されていません。delete()";
    095                throw new UnsupportedOperationException(errMsg);
    096        }
    097
    098        /**
    099         * ファイルを指定先に、コピーします。
    100         *
    101         * @param afPath コピー先
    102         * @return 成否フラグ
    103         */
    104        @Override
    105        public boolean copy(String afPath) {
    106                String errMsg = "このクラスでは実装されていません。copy(String)";
    107                throw new UnsupportedOperationException(errMsg);
    108        }
    109
    110        /**
    111         * ファイルを指定先に、移動します。
    112         *
    113         * @param afPath 移動先
    114         * @return 成否フラグ
    115         */
    116        @Override
    117        public boolean move(String afPath) {
    118                boolean flgRtn = false;
    119
    120                flgRtn = copy(afPath);
    121                if (flgRtn) {
    122                        flgRtn = delete();
    123                }
    124
    125                return flgRtn;
    126        }
    127
    128        /**
    129         * 設定パスを取得します。
    130         *
    131         * @return 設定パス
    132         */
    133        @Override
    134        public String getPath() {
    135                return path;
    136        }
    137
    138        /**
    139         * 絶対パスを取得します。
    140         *
    141         * @return 絶対パス
    142         */
    143        @Override
    144        public String getAbsolutePath() {
    145                return path;
    146        }
    147
    148        /**
    149         * 名称を取得します。
    150         *
    151         * @return 名称
    152         */
    153        @Override
    154        public String getName() {
    155                return drawName(path);
    156        }
    157
    158        /**
    159         * 親のパスを取得します。
    160         *
    161         * @return 親のパス
    162         */
    163        @Override
    164        public String getParent() {
    165                return drawParent(path);
    166        }
    167
    168        /**
    169         * ファイルサイズを返します
    170         *
    171         * @return ファイルサイズ
    172         */
    173        @Override
    174        public long length() {
    175                // TODO 自動生成されたメソッド・スタブ
    176                return 0;
    177        }
    178
    179        /**
    180         * 最終更新時刻を取得します。
    181         *
    182         * @return 最終更新時刻
    183         */
    184        @Override
    185        public long lastModified() {
    186                // TODO 自動生成されたメソッド・スタブ
    187                return 0;
    188        }
    189
    190        /**
    191         * ファイルの場合は、trueを返します。
    192         *
    193         * @return ファイルフラグ
    194         */
    195        @Override
    196        public boolean isFile() {
    197                // TODO 自動生成されたメソッド・スタブ
    198                return false;
    199        }
    200
    201        /**
    202         * ディレクトリの場合は、trueを返します。
    203         *
    204         * @return ディレクトリフラグ
    205         */
    206        @Override
    207        public boolean isDirectory() {
    208                // TODO 自動生成されたメソッド・スタブ
    209                return false;
    210        }
    211
    212        /**
    213         * 存在する場合は、trueを返します。
    214         *
    215         * @return 存在フラグ
    216         */
    217        @Override
    218        public boolean exists() {
    219                return isDirectory() | isFile();
    220        }
    221
    222        /**
    223         * パスのファイルとディレクトリ一覧を取得します。
    224         *
    225         * @return ファイルとティレクトリ一覧
    226         */
    227        @Override
    228        public FileOperation[] listFiles() {
    229                return listFiles(new HybsFileFilter());
    230        }
    231
    232        /**
    233         * パスのファイルとディレクトリ一覧を取得して、
    234         * 引数でフィルターを行います。
    235         *
    236         * @param filter フィルター
    237         * @return      ファイルとディレクトリ一覧
    238         */
    239        @Override
    240        public FileOperation[] listFiles(FileOperationFileFilter filter) {
    241                String errMsg = "このクラスでは実装されていません。listFiles(FileOperationFileFilter)";
    242                throw new UnsupportedOperationException(errMsg);
    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         * @return 成否フラグ
    267         */
    268        @Override
    269        public boolean mkdirs() {
    270                return true;
    271        }
    272
    273        /**
    274         * 指定のファイル情報のファイル名に変更します。
    275         *
    276         * @param dest 変更後のファイル情報
    277         * @return 成否フラグ
    278         */
    279        @Override
    280        public boolean renameTo(FileOperation dest) {
    281                return move(dest.getPath());
    282        }
    283
    284        /**
    285         * 親のディレクトリを返します。
    286         *
    287         * @return 親のディレクトリ
    288         */
    289        @Override
    290        public FileOperation getParentFile() {
    291                return null;
    292        }
    293
    294        /**
    295         * 書き込み可能フラグ
    296         *
    297         * ※クラウドストレージの場合は、
    298         * 必ずtrueを返します。
    299         *
    300         * @return 書き込み可能フラグ
    301         */
    302        @Override
    303        public boolean canWrite() {
    304                return true;
    305        }
    306
    307        /**
    308         * 読み取り可能フラグ
    309         *
    310         * ※クラウドストレージの場合は、
    311         * 必ずtrueを返します。
    312         *
    313         * @return 読み取り可能フラグ
    314         */
    315        @Override
    316        public boolean canRead() {
    317                return true;
    318        }
    319
    320        /**
    321         * 隠しファイルフラグ
    322         *
    323         * ※クラウドストレージの場合は、
    324         * 必ずfalseを返します。
    325         *
    326         * @return 隠しファイルフラグ
    327         */
    328        @Override
    329        public boolean isHidden() {
    330                return false;
    331        }
    332
    333        /**
    334         * 新規ファイル作成
    335         *
    336         * 既にファイルが存在しない場合のみ、
    337         * 空のファイルを作成します。
    338         *
    339         * @return 成否フラグ
    340         * @throws IOException
    341         */
    342        @Override
    343        public boolean createNewFile() throws IOException {
    344                boolean rtn = false;
    345
    346                if (!exists()) {
    347                        InputStream is = null;
    348                        try {
    349                                is = new ByteArrayInputStream(new byte[0]);
    350                                write(is);
    351                                rtn = true;
    352                        } finally {
    353                                Closer.ioClose(is);
    354                        }
    355                }
    356
    357                return rtn;
    358        }
    359
    360        /**
    361         * 最終更新時刻の更新
    362         *
    363         * 最終更新時刻の更新を行います。
    364         * ※クラウドストレージの場合は、
    365         * 最終更新時刻の更新を行えません。
    366         *
    367         * @param time 更新する最終更新時刻
    368         * @return 成否フラグ
    369         */
    370        @Override
    371        public boolean setLastModified(long time) {
    372                // クラウドストレージでは、setLastModifiedによる、
    373                // 最終更新時刻の設定はできないので、
    374                // 処理を行わずにtrueを返します。
    375                return true;
    376        }
    377
    378        /**
    379         * カノニカルファイル情報の取得
    380         *
    381         * ※ローカルサーバのみ通常ファイルと、
    382         * カノニカルファイルで異なります。
    383         *
    384         * @return カノニカルファイル情報
    385         * @throws IOException
    386         */
    387        @Override
    388        public FileOperation getCanonicalFile() throws IOException {
    389                return this;
    390        }
    391
    392        /**
    393         * toStringメソッド
    394         * パスを返します。
    395         */
    396        @Override
    397        public String toString() {
    398                return path;
    399        }
    400
    401        /** 共通関数 **/
    402        /**
    403         * ファイルパスの編集 2018/05/07 ADD
    404         * パスの先頭が「/」の場合は「/」の除去と、「//」を「/」に置換処理の追加。
    405         *
    406         * @og.rev 5.9.32.1 (2018/05/11)
    407         * @param path
    408         * @return 変更後パス
    409         */
    410        protected String editPath(final String path) {
    411                if (StringUtil.isNull(path)) {
    412                        return "";
    413                }
    414
    415                String rtn = path;
    416                // 先頭が「/」の場合は除去
    417                if ("/".equals(rtn.substring(0, 1))) {
    418                        rtn = rtn.substring(1);
    419                }
    420                // 「//」は「/」に置換
    421                rtn = rtn.replaceAll("//", "/");
    422                // 後尾の「.」は除去
    423                rtn = rTrim(rtn, '.');
    424                // 後尾の「/」は除去
    425                rtn = rTrim(rtn, '/');
    426
    427                return rtn;
    428        }
    429
    430        /**
    431         * キーから親のパスを抽出します。
    432         *
    433         * @param key キー
    434         * @return 親のパス
    435         */
    436        protected String drawParent(String key) {
    437                int k = key.lastIndexOf("/");
    438
    439                String rtn = "";
    440                if (k > 0) {
    441                        rtn = key.substring(0, key.lastIndexOf("/"));
    442                }
    443                if ("/".equals(File.separator)) {
    444                        rtn = File.separator + rtn;
    445                }
    446
    447                return rtn;
    448        }
    449
    450        /**
    451         * 引数のkeyから名称を抽出します。
    452         *
    453         * @param key キー(パス)
    454         * @return 名称
    455         */
    456        protected String drawName(String key) {
    457                int k = key.lastIndexOf("/");
    458
    459                String rtn = key;
    460                if (k > 0) {
    461                        rtn = key.substring(key.lastIndexOf("/") + 1);
    462                }
    463                return rtn;
    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         * @param str 対象文字列
    488         * @param chr 指定文字
    489         * @return 右側から指定文字を除去後の文字列
    490         */
    491        protected String rTrim(final String str, char chr) {
    492                String rtn = str;
    493                int trgPos = 0;
    494                for (int i = str.length() - 1; i >= 0; i--) {
    495                        if (str.charAt(i) == chr) {
    496                                trgPos = i;
    497                                // すべて合致した場合は、から文字を返す
    498                                if (trgPos == 0) {
    499                                        rtn = "";
    500                                }
    501                        } else {
    502                                break;
    503                        }
    504                }
    505
    506                if (trgPos > 0) {
    507                        rtn = str.substring(0, trgPos);
    508                }
    509
    510                return rtn;
    511        }
    512
    513        /**
    514         * ファイル区切り文字を変換します。
    515         *
    516         * @param path 変換前文字列
    517         * @return 返還後文字列
    518         */
    519        protected String replaceFileSeparetor(final String path) {
    520                if (StringUtil.isNull(path)) {
    521                        return "";
    522                }
    523
    524                return path.replaceAll("\\\\", "/");
    525        }
    526
    527        /**
    528         * フィルター処理を行う
    529         *
    530         * @param list フィルタを行うリスト
    531         * @param filter フィルタ情報
    532         * @return フィルタ後のリスト
    533         */
    534        protected FileOperation[] filter(List<FileOperationInfo> list, FileOperationFileFilter filter) {
    535                ArrayList<FileOperationInfo> files = new ArrayList<FileOperationInfo>();
    536                for (int i = 0; i < list.size(); i++) {
    537                        if (filter.accept(list.get(i))) {
    538                                files.add(list.get(i));
    539                        }
    540                }
    541                return files.toArray(new FileOperationInfo[files.size()]);
    542        }
    543
    544        /**
    545         * InputStreamをbyte[]に変換。
    546         * InputStreamのサイズ計算に利用。
    547         *
    548         * @param is byte[]変換するInputStream
    549         * @return InpusStreamをbyte[]に変換した値
    550         */
    551        protected byte[] toByteArray(InputStream is) throws IOException {
    552                ByteArrayOutputStream output = new ByteArrayOutputStream();
    553                try {
    554                        byte[] b = new byte[BUFFER_SIZE];
    555                        int n = 0;
    556                        while ((n = is.read(b)) != -1) {
    557                                output.write(b, 0, n);
    558                        }
    559                        return output.toByteArray();
    560                } finally {
    561                        output.close();
    562                }
    563        }
    564}
    565