package com.example.myapplication;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
class XmlReader {
@NonNull private static final String TAG = XmlReader.class.getSimpleName();
/**
* 各要素のタグ名称
/
@NonNull private final String TARGET = "target";
@NonNull private final String TARGET_LIST = "targetList";
@NonNull private final String TARGET_NUM = "targetNum";
@NonNull private final String TARGET_NAME = "targetName";
@NonNull private final String TARGET_ID = "targetId";
@NonNull private final String EXPIRATION_DATA = "expirationDate";
/*
* targetListの要素数
/
private final int TARGET_LIST_NUM = 1;
/*
* targetIdの要素数
/
private final int TARGET_ID_NUM = 1;
/*
* expirationDateの要素数
/
private final int TARGET_EXPIRATION_DATE_NUM = 1;
/*
* targetNumの要素数の最大値
/
private final int TARGET_NUM_MAX = 2;
/*
* targetNumの要素数の最小値
*/
private final int TARGET_NUM_MIN = 1;
/**
* ファイル検索に使用するnameのリスト
*/
@Nullable
private List<Node> mNameElementList;
/**
* name要素取得
*
* @return name要素のリスト
*/
@Nullable
public List<Node> getNameElementList() {
Log.i(TAG, "getNameElementList()");
return mNameElementList;
}
/**
* DOMによるxml読み込み処理
*
* @param inputStream 読み込み対象XML
* @return true:正常なXML, false:不正なXML
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/
public boolean domRead(InputStream inputStream) throws SAXException, IOException, ParserConfigurationException {
Log.i(TAG, "domRead()");
// 初期化
mNameElementList = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
boolean result = false;
// ルート要素取得
Element root = document.getDocumentElement();
if (null != root) {
if (TARGET.equals(root.getTagName())) {
Log.i(TAG, "root.getTagName() : " + root.getTagName());
//ルートからexpirationDateを取得
NodeList expirationDate = root.getElementsByTagName(EXPIRATION_DATA);
if (checkExpirationDate(expirationDate)) {
//ルートからtargetIdを取得
NodeList targetId = root.getElementsByTagName(TARGET_ID);
if (checkTargetId(targetId)) {
//ルートからtargetListを取得
NodeList targetList = root.getElementsByTagName(TARGET_LIST);
if (checkTargetList(targetList)) {
result = true;
} else {
Log.i(TAG, "Error : targetList is invalid");
}
} else {
Log.i(TAG, "Error : targetId is invalid");
}
} else {
Log.i(TAG, "Error : expirationDate is invalid");
}
} else {
Log.i(TAG, "Error : target tag name is invalid");
}
} else {
Log.i(TAG, "Error : Root is null");
}
return result;
}
/**
* targetListのチェック
*
* @param targetList チェック対象のNodeList
* @return true:正常なtargetList, false:不正なtargetList
*/
private boolean checkTargetList(@Nullable NodeList targetList) {
Log.i(TAG, "checkTargetList()");
boolean result = false;
if (null != targetList) {
if (TARGET_LIST_NUM == targetList.getLength()) {
Element targetListElement = (Element) targetList.item(0);
if (null != targetListElement) {
NodeList targetListChildren = targetListElement.getChildNodes();
if (null != targetListChildren) {
result = checkTargetListChildren(targetListChildren);
} else {
Log.i(TAG, "Error : targetList children is null");
}
} else {
Log.i(TAG, "Error : targetList is null");
}
} else {
Log.i(TAG, "Error : targetList is invalid configuration");
}
} else {
Log.i(TAG, "Error : targetList is null");
}
Log.i(TAG, "checkTargetList() result : " + result);
return result;
}
/**
* targetListの子要素のチェック
*
* @param targetListChildren チェック対象のNodeList
* @return true:正常なtargetListの子要素, false:不正なtargetListの子要素
*/
private boolean checkTargetListChildren(@NonNull NodeList targetListChildren) {
Log.i(TAG, "checkTargetListChildren()");
List<Node> targetNumList = new ArrayList<>();
List<Node> targetNameList = new ArrayList<>();
boolean result = false;
for (int i = 0; i < targetListChildren.getLength(); i++) {
Node node = targetListChildren.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
String nodeName = node.getNodeName();
Log.i(TAG, "nodeName : " + nodeName);
if (TARGET_NUM.equals(nodeName)) {
targetNumList.add(node);
} else if (TARGET_NAME.equals(nodeName)) {
targetNameList.add(node);
} else {
Log.i(TAG, "Error : element tag name is invalid");
break;
}
}
}
result = targetNumWithTargetNameVerification(targetNumList, targetNameList);
Log.i(TAG, "checkTargetListChildren() result : " + result);
return result;
}
/**
* targetNumとtargetNameの整合性確認
*
* @param targetNumList 確認対象のtargetNumList
* @param targetNameList 確認対象のtargetNameList
* @return true:整合OK, false:整合NG
*/
private boolean targetNumWithTargetNameVerification(@NonNull List<Node> targetNumList, @NonNull List<Node> targetNameList) {
Log.i(TAG, "targetNumWithTargetNameVerification()");
boolean result = false;
// targetNumの要素数確認
if (TARGET_ID_NUM == targetNumList.size()) {
int targetNum = 0;
try {
// targetNumの要素取得
targetNum = Integer.parseInt(targetNumList.get(0).getTextContent());
} catch (@NonNull NumberFormatException | DOMException | IndexOutOfBoundsException e) {
e.printStackTrace();
}
// targetNumの整合性を確認
if (TARGET_NUM_MIN == targetNum || TARGET_NUM_MAX == targetNum) {
// targetNumの値とtargetNameの数が一致しているか確認
if (targetNum == targetNameList.size()) {
Log.i(TAG, "Success : targetElement is valid");
result = true;
mNameElementList = targetNameList;
} else {
Log.i(TAG, "Error : The number of targetNum does not match the targetName");
}
} else {
Log.i(TAG, "Error : targetNum is invalid");
}
} else {
Log.i(TAG, "Error : targetNum is invalid");
}
Log.i(TAG, "targetNumWithTargetNameVerification() result : " + result);
return result;
}
/**
* expirationDateのチェック
*
* @param expirationDate チェック対象のNodeList
* @return true:正常なexpirationDate, false:不正なexpirationDate
*/
private boolean checkExpirationDate(@Nullable NodeList expirationDate) {
Log.i(TAG, "checkExpirationDate()");
String expirationDateString = null;
boolean result = false;
if (null != expirationDate) {
if (TARGET_EXPIRATION_DATE_NUM == expirationDate.getLength()) {
Node node = expirationDate.item(0);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if (EXPIRATION_DATA.equals(element.getNodeName())) {
try {
expirationDateString = element.getTextContent();
} catch (DOMException e) {
e.printStackTrace();
}
if (null != expirationDateString) {
result = expirationDateVerification(expirationDateString);
} else {
Log.i(TAG, "Error : expirationDateString is null");
}
} else {
Log.i(TAG, "Error : element tag name is invalid");
}
} else {
Log.i(TAG, "Error : expirationDate element is invalid");
}
} else {
Log.i(TAG, "Error : expirationDate is invalid configuration");
}
} else {
Log.i(TAG, "Error : expirationDate is null");
}
Log.i(TAG, "checkExpirationDate() result : " + result);
return result;
}
/**
* expirationDateの整合性確認
*
* @param expirationDateString チェック対象のexpirationDate
* @return true:正常な要素, false:不正な要素
*/
private boolean expirationDateVerification(@NonNull String expirationDateString) {
Log.i(TAG, "expirationDateVerification()");
// 現在時刻取得
LocalDateTime nowDate = LocalDateTime.now();
LocalDateTime expirationDate = null;
try {
// expirationDateをLocalDateTimeに変換
expirationDate = expirationDateConversion(expirationDateString);
} catch (@NonNull DateTimeParseException | IllegalArgumentException e) {
e.printStackTrace();
}
// 現在時刻とexpirationDateの比較
Log.i(TAG, "nowDate : " + nowDate + ", expirationDate : " + expirationDate);
boolean result = false;
if (null != nowDate && null != expirationDate) {
// 有効期限内
if (nowDate.isBefore(expirationDate)) {
Log.i(TAG, "Success : Within the expiration date");
result = true;
// 有効期限と同時刻
} else if (nowDate.isEqual(expirationDate)) {
Log.i(TAG, "Success : Expiration date is just");
result = true;
// 有効期限切れ
} else {
Log.i(TAG, "Error : Expired");
}
} else {
Log.i(TAG, "Error : Verification failure");
}
Log.i(TAG, "expirationDateVerification() result : " + result);
return result;
}
/**
* String(yyyyMMddHHmmss)からLocalDateTimeに変換
*
* @return LocalDateTime型の日付(変換対象がnullの場合 、 null)
*/
@Nullable
private LocalDateTime expirationDateConversion(@NonNull String expirationDateString) {
Log.i(TAG, "expirationDateConversion() expirationDateString : " + expirationDateString);
LocalDateTime dateTime = null;
if (expirationDateString.length() == 14) {
dateTime = LocalDateTime.of(
Integer.parseInt(expirationDateString.substring(0, 4)), // 年
Integer.parseInt(expirationDateString.substring(4, 6)), // 月
Integer.parseInt(expirationDateString.substring(6, 8)), // 日
Integer.parseInt(expirationDateString.substring(8, 10)), // 時
Integer.parseInt(expirationDateString.substring(10, 12)), // 分
Integer.parseInt(expirationDateString.substring(12, 14))); // 秒
} else {
Log.i(TAG, "Error : ExpirationDate is invalid");
}
return dateTime;
}
/**
* targetIdのチェック
*
* @param targetId チェック対象のNodeList
* @return true:正常なtargetId, false:不正なtargetId
*/
private boolean checkTargetId(@Nullable NodeList targetId) {
Log.i(TAG, "checkTargetId()");
String targetIdString = null;
boolean result = false;
if (null != targetId) {
if (TARGET_ID_NUM == targetId.getLength()) {
Node node = targetId.item(0);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if (TARGET_ID.equals(element.getNodeName())) {
try {
targetIdString = element.getTextContent();
} catch (DOMException e) {
e.printStackTrace();
}
if (null != targetIdString) {
Log.i(TAG, "Success : checkTargetId() targetIdString : " + targetIdString);
result = true;
} else {
Log.i(TAG, "Error : targetIdString is null");
}
} else {
Log.i(TAG, "Error : element tag name is invalid");
}
} else {
Log.i(TAG, "Error : targetId element is invalid");
}
} else {
Log.i(TAG, "Error : targetId is invalid configuration");
}
} else {
Log.i(TAG, "Error : targetId is null");
}
Log.i(TAG, "checkTargetId() result : " + result);
return result;
}
}