##### Coverage Report - jp.co.y_net.amm.dao.TextDao

Classes in this File | Line Coverage | Branch Coverage | Complexity

TextDao

0% | 0/187

0% | 0/56

0.0;0

TextDao$1

0% | 0/4

0% | 0/4

0.0;0

TextDao$TextDBAccSampleDto

0% | 0/8

N/A | N/A

0.0;0

1

0

     package jp.co.y_net.amm.dao;

2

3

4

     import java.io.BufferedReader;

5

     import java.io.BufferedWriter;

6

     import java.io.File;

7

     import java.io.FileFilter;

8

     import java.io.FileInputStream;

9

     import java.io.FileOutputStream;

10

     import java.io.IOException;

11

     import java.io.InputStreamReader;

12

     import java.io.OutputStream;

13

     import java.io.OutputStreamWriter;

14

     import java.io.Writer;

15

     import java.lang.reflect.Field;

16

     import java.nio.charset.Charset;

17

     import java.util.ArrayList;

18

     import java.util.Arrays;

19

     import java.util.Collections;

20

     import java.util.List;

21

22

     import javax.servlet.ServletContext;

23

24

     import org.apache.wicket.protocol.http.WebApplication;

25

26

     import com.fasterxml.jackson.core.JsonProcessingException;

27

     import com.fasterxml.jackson.databind.ObjectMapper;

28

29

     /**

30

     * テキストファイルをストレージとするData Access Object

31

     *

32

     * オブジェクトはJSON形式に変換する。

33

     *

34

     * 必須ライブラリは、親プロジェクトの pom.xml に記述

35

     *

36

             <!-- Jackson -->

37

             <dependency>

38

                 <groupId>com.fasterxml.jackson.core</groupId>

39

                 <artifactId>jackson-core</artifactId>

40

                 <version>2.5.0</version>

41

             </dependency>

42

             <dependency>

43

                 <groupId>com.fasterxml.jackson.core</groupId>

44

                 <artifactId>jackson-databind</artifactId>

45

                 <version>2.5.0</version>

46

             </dependency>

47

             <dependency>

48

                 <groupId>com.fasterxml.jackson.core</groupId>

49

                 <artifactId>jackson-annotations</artifactId>

50

                 <version>2.5.0</version>

51

             </dependency>

52

     *

53

     * @author k.inaba

54

     */

55

     public class TextDao {

56

57

          /*

58

          * --------------------------------------------------------------------------

59

          * サンプル実装

60

          */

61

62

          /**

63

          * 実装のサンプル このDAOの使用方法を示す。

64

          * @param args パラメータ不要

65

          */

66

          public static void main(String[] args) {

67

68

               /*

69

               * DAOをインスタンス化する。

70

               * このとき保存先を指定する。

71

               */

72

0

               TextDao dao = new TextDao("C:\\tmp\\textdb");

73

74

               /* 登録のサンプル */

75

76

0

               TextDBAccSampleDto insertdto1 = new TextDBAccSampleDto(10, "aiueo");

77

0

               int insertId1 = dao.insert(insertdto1);

78

0

               System.out.println(insertdto1.toString() + "を[" + insertId1 + "]として保存しました。");

79

80

0

               TextDBAccSampleDto insertdto2 = new TextDBAccSampleDto(10, "あいうえお");

81

0

               int insertId2 = dao.insert(insertdto2);

82

0

               System.out.println(insertdto2.toString() + "を[" + insertId2 + "]として保存しました。");

83

84

               /* 検索のサンプル*/

85

86

0

               TextDBAccSampleDto condA = new TextDBAccSampleDto();

87

0

               condA.col1 = 10;

88

0

               List<TextDBAccSampleDto> resultsA = dao.select(condA, TextDBAccSampleDto.class);

89

90

0

               System.out.println(condA.toString() + " を条件として検索を実行。");

91

0

               for (TextDBAccSampleDto dto: resultsA) {

92

0

                    System.out.println(">" + dto.toString());

93

               }

94

95

0

               TextDBAccSampleDto condB = new TextDBAccSampleDto();

96

0

               condB.col1 = 10;

97

0

               condB.col2 = "あいうえお";

98

0

               List<TextDBAccSampleDto> resultsB = dao.select(condB, TextDBAccSampleDto.class);

99

100

0

               System.out.println(condB.toString() + " を条件として検索を実行。");

101

0

               for (TextDBAccSampleDto dto: resultsB) {

102

0

                    System.out.println(">" + dto.toString());

103

               }

104

105

               /* 削除のサンプル */

106

107

0

               List<TextDBAccSampleDto> resultsAll = dao.select(TextDBAccSampleDto.class);

108

0

               Collections.reverse(resultsAll);

109

0

               int i = 0;

110

0

               for (TextDBAccSampleDto dto : resultsAll) {

111

0

                    System.out.println(dto.toString());

112

0

                    if (i > 5) {

113

0

                         System.out.println(dto.id + " を削除します。");

114

                         // dao.delete(r, false); 論理削除ではなく、実際にファイルを削除する。

115

0

                         dao.delete(dto);

116

                    }

117

0

                    i++;

118

               }

119

0

          }

120

121

          /**

122

          * 実装のサンプル このDAOで扱うDTOを実装する際の参考とする。

123

          */

124

          private static class TextDBAccSampleDto {

125

               /**

126

               * 制御用のフィールド[id]

127

               *

128

               */

129

               public int id;

130

               /* 保存するフィールド */

131

               public int col1;

132

               public String col2;

133

134

               /**

135

               * JSONからオブジェクトへ変換するために、 引数付きのコンストラクタが実装されている場合は、 デフォルトコンストラクタの実装が必要である。

136

               */

137

0

               public TextDBAccSampleDto() {

138

                    // 処理なし

139

0

               }

140

141

0

               public TextDBAccSampleDto(int col1, String col2) {

142

0

                    this.col1 = col1;

143

0

                    this.col2 = col2;

144

0

               }

145

146

               @Override

147

               public String toString() {

148

0

                    return "TextDBAccSampleBean [id=" + id + ", col1=" + col1

149

0

                              + ", col2=" + col2 + "]";

150

               }

151

          }

152

153

          /* -------------------------------------------------------------------------- */

154

155

          private File dbroot;

156

          /**

157

          * @param root データを保存するディレクトリ

158

          */

159

0

          public TextDao(String dbname) {

160

0

               dbroot = new File(getDbPath(dbname));

161

0

               if (dbroot.exists() == false) {

162

0

                    dbroot.mkdirs();

163

               }

164

0

          }

165

          /**

166

           * Tomcatインスタンスのコンテキストルートより２階層上位のディレクトリを

167

           * テキストデータを保存するディレクトリのパスとして取得する。

168

           *

169

           * Linuxでの実行環境では

170

           * 　/var/local/opt/tomcat/apache-tomcat/7.0/{???}-web/{dbname}/

171

           *

172

           * 開発環境(ローカルのEclipse)では

173

           * 　{ワークスペース}\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\{dbname}

174

           *

175

           * @return テキストデータを保存するディレクトリのパス

176

           */

177

          private static String getDbPath(String dbname) {

178

0

              ServletContext servletContext = WebApplication.get().getServletContext();

179

0

              File tomCatInstance = new File(servletContext.getRealPath("")).getParentFile().getParentFile(); // コンテキストルートより２階層上位

180

0

              File file = new File(new File(tomCatInstance, dbname), dbname + ".txt");

181

0

              if (file.exists() == false) {

182

0

                  file.getParentFile().mkdirs();

183

                  try {

184

0

                      boolean result = file.createNewFile();

185

0

                      if (result == false) {

186

0

                          throw new RuntimeException("ファイルの作成に失敗：" + file.getAbsolutePath());

187

                      }

188

0

                  } catch (IOException e) {

189

0

                      throw new RuntimeException(e);

190

                  }

191

              }

192

0

              return file.getParent();

193

          }

194

195

          /**

196

          * 保存する

197

          * @param bean 保存するデータ

198

          * @return id 保存したときに付与されたid

199

          */

200

          public int insert(Object bean) {

201

0

               String tablename = bean.getClass().getName();

202

0

               int maxId = -1;

203

0

               File[] existfiles = getDbFiles(tablename);

204

0

               for (File existfile : existfiles) {

205

0

                    int id = toId(existfile.getName(), tablename);

206

0

                    maxId = Math.max(maxId, id);

207

               }

208

0

               int insertId = maxId + 1;

209

0

               ObjectMapper objectMapper = new ObjectMapper();

210

               try {

211

0

                    String json = objectMapper.writeValueAsString(bean);

212

0

                    File f = toFile(bean.getClass(), (insertId));

213

0

                    writeText(f.getAbsolutePath(), json);

214

0

               } catch (JsonProcessingException e) {

215

0

                    throw new RuntimeException(e);

216

               }

217

0

               return insertId;

218

          }

219

220

          /**

221

          * 指定されたクラスのデータをすべて取得する。

222

          * @param clz 指定クラス

223

          * @return 取得したデータ

224

          */

225

          public <T> List<T> select(Class<T> clz) {

226

0

               return select(null, clz) ;

227

          }

228

229

          /**

230

          * 指定されたクラスのデータのうち、引数 cond の条件に合うものを取得する。

231

          *

232

          * ・cond のフィールドのうち、 nullでないフィールドが検索条件となる。

233

          * ・AND条件となる。

234

          * ・フィールド id は無視する。

235

          *

236

          * @param clz 指定クラス

237

          * @return 取得したデータ

238

          */

239

          public <T> List<T> select(T cond, Class<T> clz) {

240

0

               List<Field> cndFields = new ArrayList<Field>();

241

0

               for (Field f : clz.getFields()) {

242

0

                    if (f.getName().equals("id") == false) {

243

0

                         cndFields.add(f);

244

                    }

245

               }

246

0

               String tablename = clz.getName();

247

0

               File[] existfiles = getDbFiles(tablename);

248

0

               List<T> result = new ArrayList<T>();

249

0

               for (File file : existfiles) {

250

                    // String text = "{\"a\":123,\"b\":true,\"c\":\"あいう\"}";

251

0

                    String text = readTextAsString(file.getAbsolutePath());

252

0

                    ObjectMapper mapper = new ObjectMapper();

253

                    T bean;

254

                    try {

255

                         // JsonNode root = mapper.readTree(text);

256

                         // String c = root.get("c").asText();

257

0

                         bean = mapper.readValue(text, clz);

258

0

                    } catch (JsonProcessingException e) {

259

0

                         throw new RuntimeException(e);

260

0

                    } catch (IOException e) {

261

0

                         throw new RuntimeException(e);

262

                    }

263

264

                    /* 絞り込みのための判定 */

265

                    boolean isMatch;

266

0

                    if (cond == null) {

267

                         /* 条件なしのため必ず選択(true) */

268

0

                         isMatch = true;

269

0

                    } else {

270

0

                         isMatch = true;

271

0

                         for (Field cndField : cndFields) {

272

                              Object cndValue;

273

                              Object targetValue;

274

                              try {

275

0

                                   cndValue = cndField.get(cond);

276

0

                                   targetValue = cndField.get(bean);

277

0

                              } catch (Exception e) {

278

0

                                   throw new RuntimeException(e);

279

                              }

280

0

                              if (cndValue != null

281

0

                                        && cndValue.equals(targetValue) == false) {

282

                                   /* 不一致の条件を検出 */

283

0

                                   isMatch = false;

284

0

                                   break;

285

                              }

286

                         }

287

                    }

288

0

                    if (isMatch) {

289

                         /* beanにidを付与する */

290

                         /* ファイル名からidを取得する */

291

                         try {

292

0

                              Field f = clz.getField("id");

293

0

                              f.set(bean, toId(file.getName(), tablename));

294

0

                         } catch (NoSuchFieldException e) {

295

                              /* フィールド[id]がなければ無視する。エラーとしない。 */

296

0

                         } catch (Exception e) {

297

0

                              throw new RuntimeException(e);

298

                         }

299

0

                         result.add(bean);

300

                    }

301

               }

302

0

               return result;

303

          }

304

305

          /**

306

          * 指定されたBeanのidと一致するデータを論理削除する。

307

          * 論理削除の場合は、該当のデータの拡張子に[.del]が付与され、無効化される。

308

          * @param bean

309

          */

310

          public void delete(Object bean) {

311

0

               delete(bean, true); // デフォルトは論理削除

312

0

          }

313

          /**

314

          * 指定されたBeanのidと一致するデータを削除する。

315

          * 論理削除の場合は、該当のデータの拡張子に[.del]が付与され、無効化される。

316

          * @param bean

317

          * @param logical 論理削除とする場合はTrue, 物理削除はFalseを指定する。

318

          */

319

          private void delete(Object bean, boolean logical) {

320

               int id;

321

               try {

322

0

                    Field f = bean.getClass().getField("id");

323

0

                    id = f.getInt(bean);

324

0

               } catch (NoSuchFieldException e) {

325

0

                    throw new RuntimeException("フィールド[id]がないbeanは削除できません。", e);

326

0

               } catch (Exception e) {

327

0

                    throw new RuntimeException(e);

328

               }

329

0

               File file = toFile(bean.getClass(), id);

330

0

               if (logical) {

331

                    /* 論理削除 （ファイル名の末尾に[.del]を付与する） */

332

0

                    File dest = getDelFile(file);

333

0

                    file.renameTo(dest);

334

0

               } else {

335

0

                    file.delete();

336

               }

337

0

          }

338

339

          /**

340

          * 引数srcのファイルオブジェクトのファイル名の末尾に [.del]を付与したオブジェクトを取得する。

341

          * すでに同名のファイルが存在するときは、[.del.del]となるように 再起処理を行う。

342

          *

343

          * @param src

344

          * @return

345

          */

346

          private File getDelFile(File src) {

347

0

               File delFile = new File(src.getAbsolutePath() + ".del");

348

0

               if (delFile.exists()) {

349

0

                    return getDelFile(delFile);

350

               }

351

0

               return delFile;

352

          }

353

354

          private File toFile(Class<? extends Object> clz, int id) {

355

0

               String tablename = clz.getName();

356

0

               String filename = dbroot.getAbsolutePath() + File.separatorChar

357

0

                         + tablename + "_" + id + ".txt";

358

0

               return new File(filename);

359

          }

360

361

          private int toId(String filename, String tablename) {

362

               // Matcher m = Pattern.compile("_([0-9]+)\\.txt").matcher(tmp);

363

               // tmp = m.group(1);

364

0

               String tmp = filename;

365

0

               tmp = tmp.substring(tablename.length()); // 接頭のテーブル名を除去

366

0

               tmp = tmp.substring(1); // _を除去

367

0

               tmp = tmp.substring(0, tmp.lastIndexOf(".txt"));

368

               int id;

369

               try {

370

0

                    id = Integer.parseInt(tmp);

371

0

               } catch (NumberFormatException e) {

372

0

                    throw new RuntimeException(e);

373

               }

374

0

               return id;

375

          }

376

377

          private File[] getDbFiles(final String tablename) {

378

0

               File[] existfiles = dbroot.listFiles(new FileFilter() {

379

                    @Override

380

                    public boolean accept(File f) {

381

0

                         return (f.getName().startsWith(tablename + "_") && f.getName()

382

0

                                   .endsWith(".txt"));

383

                    }

384

               });

385

0

               return existfiles;

386

          }

387

          /*------------------------------------------------------------------------------*/

388

          private static final String DEFAULT_ENC = "UTF-8";

389

0

          public static final String FILE_SEPARATOR = File.separator;

390

0

          public static final String LINE_SEPARATOR = System.getProperty("line.separator");

391

          /**

392

           * テキストファイルを書き出す

393

           * @param filepath

394

           * @param charsetName 例:"UTF-8"

395

           * @param text

396

           */

397

          public static void writeText(String filepath, String charsetName, List<String> text) {

398

0

              File f = new File(filepath);

399

0

              OutputStream os = null;

400

0

              Writer w = null;

401

0

              BufferedWriter bw = null;

402

              try {

403

0

                  os = new FileOutputStream(f);

404

0

                  w  = new OutputStreamWriter(os, charsetName);

405

0

                  bw = new BufferedWriter(w);

406

0

                  for (String line: text) {

407

0

                      bw.write(line);

408

0

                      bw.newLine();

409

                      //bw.flush();

410

                  }

411

0

              } catch (Exception e) {

412

0

                  throw new RuntimeException(e);

413

0

              } finally {

414

                  try {

415

0

                      if (bw != null) bw.close();

416

0

                      if (w != null) w.close();

417

0

                      if (os != null) os.close();

418

0

                  } catch (IOException e) {

419

0

                      throw new RuntimeException(e);

420

                  }

421

0

              }

422

0

          }

423

          public static void writeText(String filepath, String charsetName, String text) {

424

0

              String[] array = text.split(LINE_SEPARATOR);

425

0

              List<String> list = Arrays.asList(array);

426

0

              writeText(filepath, charsetName, list);

427

0

          }

428

          public static void writeText(String filepath, List<String> string) {

429

0

              writeText(filepath, DEFAULT_ENC, string);

430

0

          }

431

          public static void writeText(String filepath, String string) {

432

0

              writeText(filepath, DEFAULT_ENC, string);

433

0

          }

434

          public static String readTextAsString(String filepath, String charsetName) {

435

0

              StringBuilder sb = new StringBuilder();

436

0

              List<String> lines = readText(filepath, charsetName);

437

0

              for (String line: lines) {

438

0

                  sb.append(line).append(LINE_SEPARATOR);

439

              }

440

0

              return sb.toString();

441

          }

442

          /**

443

           * テキストファイルを読み込む

444

           * @param filepath

445

           * @return

446

           */

447

          public static String readTextAsString(String filepath) {

448

0

              return readTextAsString(filepath, DEFAULT_ENC);

449

          }

450

          /**

451

           * テキストファイルを読み込む

452

           * @param filepath

453

           * @param charsetName 例:"UTF-8"

454

           * @return List<String>

455

           */

456

          public static List<String> readText(String filepath, String charsetName) {

457

0

              if( new File(filepath).exists() == false ) {

458

0

                  throw new RuntimeException("ファイルが見つかりません。 [" + new File(filepath).getAbsolutePath() + "]");

459

              }

460

0

              List<String> result = new ArrayList<String>();

461

0

              FileInputStream is = null;

462

0

              InputStreamReader r = null;

463

0

              BufferedReader br = null;

464

              try {

465

0

                  is = new FileInputStream(filepath);

466

0

                  r = new InputStreamReader(is, Charset.forName(charsetName));

467

0

                  br = new BufferedReader(r);

468

     //           int ch;

469

     //           while ((ch = in.read()) != -1) {

470

                  String line;

471

0

                  while((line = br.readLine()) != null) {

472

0

                      result.add(line);

473

474

                      //System.out.print(str + NEW_LINE_CODE);

475

                      /* Unicode表現でデバッグ表示 */

476

                      //System.out.print(Integer.toHexString(ch) + " ");

477

                  }

478

0

              } catch (IOException e) {

479

0

                  throw new RuntimeException(e);

480

0

              } finally {

481

                  try {

482

0

                      if (br != null) br.close();

483

0

                      if (r != null) r.close();

484

0

                      if (is != null) is.close();

485

0

                  } catch (IOException e) {

486

0

                      throw new RuntimeException(e);

487

                  }

488

0

              }

489

0

              return result;

490

          }

491

     }