/** * personium.io * Copyright 2014 FUJITSU LIMITED * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.fujitsu.dc.common.ads; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; import java.util.ArrayList; import java.util.List; import org.apache.commons.io.IOUtils; /** * ADS書き込み失敗ログへの出力処理を司るクラス. <br /> * 本クラスは singleton で実装し、スレッド間での出力を排他する。<br /> * また、プロセス間(PCSバージョン間)での出力は、別ファイルへの出力とすることで排他を考慮しない。<br /> * なお、ADS書き込み失敗ログは、実行サーバのローカルファイルシステムへ出力するため、複数サーバ間での排他は考慮しない。 */ public final class RollingAdsWriteFailureLog extends AbstractAdsWriteFailureLog { private File rotatedAdsWriteFailureLog; private LineNumberReader reader; /** * デフォルトコンストラクタ(使用不可). */ private RollingAdsWriteFailureLog() { super(); } /** * コンストラクタ. * @param rotatedAdsWriteFailureLog ローテートされたADS書き込み失敗ログファイル * @param baseDir ログ出力用ディレクトリ * @param pcsVersion PCSバージョン * @param physicalDelete ADS書き込み失敗ログを物理削除するか否かを示すフラグ(default: true) */ public RollingAdsWriteFailureLog(File rotatedAdsWriteFailureLog, String baseDir, String pcsVersion, boolean physicalDelete) { this(); this.rotatedAdsWriteFailureLog = rotatedAdsWriteFailureLog; this.baseDir = baseDir; this.pcsVersion = pcsVersion; this.isPhysicalDelete = physicalDelete; } /** * ローテートされたADS書き込み失敗ログファイル名からファイルの作成時刻を取得する. * @param pcsVersion PCSのバージョン * @param rotatedAdsWriteFailureLog ローテートされたADS書き込み失敗ログファイル * @return 取得したファイルの作成時刻 * @throws AdsWriteFailureLogException ローテートされたADS書き込み失敗ログファイルが存在しない、またはファイル名の書式が正しくない場合 */ public static long getCreatedTimeFromFileName(String pcsVersion, File rotatedAdsWriteFailureLog) throws AdsWriteFailureLogException { final String messageFormat = "Illegal Rotated adsWriteFailureLog file name format. [%s]"; if (!rotatedAdsWriteFailureLog.isFile()) { // ファイルが存在しない場合は異常状態とみなしてエラーとする。 String message = String.format("Rotated adsWriteFailureLog is not found. [%s]", rotatedAdsWriteFailureLog.getAbsolutePath()); throw new AdsWriteFailureLogException(message); } String fileName = rotatedAdsWriteFailureLog.getName(); String fileFormat = String.format(LOGNAME_FORMAT_ROTATE, pcsVersion, 0); String filePattern = fileFormat.substring(0, fileFormat.length() - 1); long createdTime = -1L; if (fileName.startsWith(filePattern)) { String createdTimeStr = fileName.replace(filePattern, ""); try { createdTime = Long.parseLong(createdTimeStr); } catch (NumberFormatException e) { String message = String.format(messageFormat, rotatedAdsWriteFailureLog.getAbsolutePath()); if (fileName.endsWith(LOGICAL_DELETED_LOGNAME_SUFFIX)) { message = String.format("Logical deleted adsWriteFailureLog file. [%s]", rotatedAdsWriteFailureLog.getAbsolutePath()); } throw new AdsWriteFailureLogException(message); } } else { String message = String.format(messageFormat, rotatedAdsWriteFailureLog.getAbsolutePath()); throw new AdsWriteFailureLogException(message); } return createdTime; } /** * ローテートされたADS書き込み失敗ログをオープンする. * @throws AdsWriteFailureLogException ADS書き込み失敗ログのオープンに失敗した場合 */ public void openRotatedFile() throws AdsWriteFailureLogException { try { // default encoding(UTF-8) reader = new LineNumberReader(new BufferedReader(new FileReader(this.rotatedAdsWriteFailureLog))); } catch (FileNotFoundException e) { String messsage = String.format("Failed to open rotated adsWriteFailureLog. [%s]", rotatedAdsWriteFailureLog.getAbsolutePath()); throw new AdsWriteFailureLogException(messsage, e); } } /** * ローテートされたADS書き込み失敗ログをクローズする. */ public synchronized void closeRotatedFile() { if (null == reader) { logger.info("Acitve adsWriteFailureLog is not opened."); return; } IOUtils.closeQuietly(reader); } /** * 引数で渡されたバッファにADS書き込み失敗ログを読み込む. * @param recordNum 読み込む行数 * @return 読み込んだログデータのリスト * @throws AdsWriteFailureLogException ADS書き込み失敗ログの読み込みに失敗した場合 */ public List<String> readAdsFailureLog(int recordNum) throws AdsWriteFailureLogException { try { if (null == this.reader) { reader = new LineNumberReader(new BufferedReader(new FileReader(this.rotatedAdsWriteFailureLog))); } List<String> logRecords = new ArrayList<String>(); for (int i = 0; i < recordNum; i++) { String aRecord = reader.readLine(); if (null == aRecord) { break; } logRecords.add(aRecord); } return logRecords; } catch (IOException e) { String messsage = String.format("Failed to read rotated adsWriteFailureLog. [%s]", rotatedAdsWriteFailureLog.getAbsolutePath()); throw new AdsWriteFailureLogException(messsage, e); } } /** * ローテートされたADS書き込み失敗ログを削除する. <br /> * @throws AdsWriteFailureLogException ログの削除に失敗した場合 */ public synchronized void deleteRotatedLog() throws AdsWriteFailureLogException { closeRotatedFile(); super.deleteRotatedLog(rotatedAdsWriteFailureLog); } }