4 * License : The MIT License
5 * Copyright(c) 2012 olyutorskii
8 package jp.sfjp.jindolf.config;
10 import java.io.BufferedInputStream;
11 import java.io.BufferedOutputStream;
12 import java.io.BufferedReader;
13 import java.io.BufferedWriter;
15 import java.io.FileInputStream;
16 import java.io.FileNotFoundException;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.InputStreamReader;
21 import java.io.OutputStream;
22 import java.io.OutputStreamWriter;
23 import java.io.Reader;
24 import java.io.Writer;
25 import java.nio.charset.Charset;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
28 import jp.sourceforge.jovsonz.JsComposition;
29 import jp.sourceforge.jovsonz.JsObject;
30 import jp.sourceforge.jovsonz.JsParseException;
31 import jp.sourceforge.jovsonz.JsTypes;
32 import jp.sourceforge.jovsonz.JsVisitException;
33 import jp.sourceforge.jovsonz.Json;
38 public class ConfigStore {
41 public static final File HIST_FILE = new File("searchHistory.json");
43 public static final File DRAFT_FILE = new File("draft.json");
45 public static final File NETCONFIG_FILE = new File("netconfig.json");
47 public static final File TALKCONFIG_FILE = new File("talkconfig.json");
49 private static final String LOCKFILE = "lock";
51 private static final Charset CHARSET_JSON = Charset.forName("UTF-8");
53 private static final Logger LOGGER = Logger.getAnonymousLogger();
56 private boolean useStoreFile;
57 private boolean isImplicitPath;
58 private File configPath;
63 * @param useStoreFile 設定ディレクトリへの永続化機能を使うならtrue
64 * @param configPath 設定ディレクトリ。
65 * 設定ディレクトリを使わない場合は無視され、nullとして扱われる。
67 public ConfigStore(boolean useStoreFile, File configPath ){
68 this(useStoreFile, true, configPath);
74 * @param useStoreFile 設定ディレクトリへの永続化機能を使うならtrue
75 * @param isImplicitPath コマンドラインで指定されたディレクトリならfalse
76 * @param configPath 設定ディレクトリ。
77 * 設定ディレクトリを使わない場合は無視され、nullとして扱われる。
79 public ConfigStore(boolean useStoreFile,
80 boolean isImplicitPath,
84 this.useStoreFile = useStoreFile;
86 if(this.useStoreFile){
87 this.isImplicitPath = isImplicitPath;
89 this.isImplicitPath = true;
92 if(this.useStoreFile){
93 this.configPath = configPath;
95 this.configPath = null;
103 * 設定ディレクトリを使うか否か判定する。
104 * @return 設定ディレクトリを使うならtrue。
106 public boolean useStoreFile(){
107 return this.useStoreFile;
112 * @return 設定ディレクトリ。設定ディレクトリを使わない場合はnull
114 public File getConfigPath(){
116 if(this.useStoreFile) result = this.configPath;
122 * 設定ディレクトリの存在を確認し、なければ作る。
123 * <p>設定ディレクトリを使わない場合は何もしない。
125 public void prepareConfigDir(){
126 if( ! this.useStoreFile ) return;
128 if( ! this.configPath.exists() ){
130 ConfigFile.buildConfigDirectory(this.configPath,
131 this.isImplicitPath );
132 ConfigFile.checkAccessibility(created);
134 ConfigFile.checkAccessibility(this.configPath);
143 public void tryLock(){
144 if( ! this.useStoreFile ) return;
146 File lockFile = new File(this.configPath, LOCKFILE);
147 InterVMLock lock = new InterVMLock(lockFile);
151 if( ! lock.isFileOwner() ){
152 ConfigFile.confirmLockError(lock);
153 if( ! lock.isFileOwner() ){
154 this.useStoreFile = false;
155 this.configPath = null;
163 * 設定ディレクトリ上のOBJECT型JSONファイルを読み込む。
164 * @param file JSONファイルの相対パス。
165 * @return JSON object。
167 * もしくはJSONファイルが存在しない、
171 public JsObject loadJsObject(File file){
172 JsComposition<?> root = loadJson(file);
173 if(root == null || root.getJsTypes() != JsTypes.OBJECT) return null;
174 JsObject result = (JsObject) root;
179 * 設定ディレクトリ上のJSONファイルを読み込む。
180 * @param file JSONファイルの相対パス
181 * @return JSON objectまたはarray。
183 * もしくはJSONファイルが存在しない、
186 public JsComposition<?> loadJson(File file){
187 if( ! this.useStoreFile ) return null;
190 if(file.isAbsolute()){
193 if(this.configPath == null) return null;
194 absFile = new File(this.configPath, file.getPath());
195 if( ! absFile.exists() ) return null;
196 if( ! absFile.isAbsolute() ) return null;
198 String absPath = absFile.getPath();
202 istream = new FileInputStream(absFile);
203 }catch(FileNotFoundException e){
207 istream = new BufferedInputStream(istream);
209 JsComposition<?> root;
211 root = loadJson(istream);
212 }catch(IOException e){
213 LOGGER.log(Level.SEVERE,
216 + "]の読み込み時に支障がありました。", e);
218 }catch(JsParseException e){
219 LOGGER.log(Level.SEVERE,
222 + "]の内容に不備があります。", e);
227 }catch(IOException e){
228 LOGGER.log(Level.SEVERE,
231 + "]を閉じることができません。", e);
240 * バイトストリーム上のJSONデータを読み込む。
241 * <p>バイトストリームはUTF-8と解釈される。
243 * @return JSON objectまたはarray。
244 * @throws IOException 入力エラー
245 * @throws JsParseException 構文エラー
247 protected JsComposition<?> loadJson(InputStream is)
248 throws IOException, JsParseException {
249 Reader reader = new InputStreamReader(is, CHARSET_JSON);
250 reader = new BufferedReader(reader);
251 JsComposition<?> root = loadJson(reader);
256 * 文字ストリーム上のJSONデータを読み込む。
257 * @param reader 文字ストリーム
258 * @return JSON objectまたはarray。
259 * @throws IOException 入力エラー
260 * @throws JsParseException 構文エラー
262 protected JsComposition<?> loadJson(Reader reader)
263 throws IOException, JsParseException {
264 JsComposition<?> root = Json.parseJson(reader);
269 * 設定ディレクトリ上のJSONファイルに書き込む。
270 * @param file JSONファイルの相対パス
271 * @param root JSON objectまたはarray
272 * @return 正しくセーブが行われればtrue。
273 * 何らかの理由でセーブが完了できなければfalse
275 public boolean saveJson(File file, JsComposition<?> root){
276 if( ! this.useStoreFile ) return false;
278 // TODO テンポラリファイルを用いたより安全なファイル更新
279 File absFile = new File(this.configPath, file.getPath());
280 String absPath = absFile.getPath();
284 if(absFile.createNewFile() != true) return false;
285 }catch(IOException e){
286 LOGGER.log(Level.SEVERE,
289 + "]の新規生成ができません。", e);
293 OutputStream ostream;
295 ostream = new FileOutputStream(absFile);
296 }catch(FileNotFoundException e){
300 ostream = new BufferedOutputStream(ostream);
303 saveJson(ostream, root);
304 }catch(JsVisitException e){
305 LOGGER.log(Level.SEVERE,
308 + "]の出力処理で支障がありました。", e);
310 }catch(IOException e){
311 LOGGER.log(Level.SEVERE,
314 + "]の書き込み時に支障がありました。", e);
319 }catch(IOException e){
320 LOGGER.log(Level.SEVERE,
323 + "]を閉じることができません。", e);
332 * バイトストリームにJSONデータを書き込む。
333 * <p>バイトストリームはUTF-8と解釈される。
334 * @param os バイトストリーム出力
335 * @param root JSON objectまたはarray
336 * @throws IOException 出力エラー
337 * @throws JsVisitException 構造エラー
339 protected void saveJson(OutputStream os, JsComposition<?> root)
340 throws IOException, JsVisitException {
341 Writer writer = new OutputStreamWriter(os, CHARSET_JSON);
342 writer = new BufferedWriter(writer);
343 saveJson(writer, root);
348 * 文字ストリームにJSONデータを書き込む。
349 * @param writer 文字ストリーム出力
350 * @param root JSON objectまたはarray
351 * @throws IOException 出力エラー
352 * @throws JsVisitException 構造エラー
354 protected void saveJson(Writer writer, JsComposition<?> root)
355 throws IOException, JsVisitException {
356 Json.dumpJson(writer, root);
362 * @return 履歴データ。履歴を読まないもしくは読めない場合はnull
364 public JsObject loadHistoryConfig(){
365 JsObject result = loadJsObject(HIST_FILE);
371 * @return 原稿データ。原稿を読まないもしくは読めない場合はnull
373 public JsObject loadDraftConfig(){
374 JsObject result = loadJsObject(DRAFT_FILE);
380 * @return ネットワーク設定データ。
381 * 設定を読まないもしくは読めない場合はnull
383 public JsObject loadNetConfig(){
384 JsObject result = loadJsObject(NETCONFIG_FILE);
391 * 設定を読まないもしくは読めない場合はnull
393 public JsObject loadTalkConfig(){
394 JsObject result = loadJsObject(TALKCONFIG_FILE);
401 * @return 書き込まなかったもしくは書き込めなかった場合はfalse
403 public boolean saveHistoryConfig(JsComposition<?> root){
404 boolean result = saveJson(HIST_FILE, root);
411 * @return 書き込まなかったもしくは書き込めなかった場合はfalse
413 public boolean saveDraftConfig(JsComposition<?> root){
414 boolean result = saveJson(DRAFT_FILE, root);
420 * @param root ネットワーク設定
421 * @return 書き込まなかったもしくは書き込めなかった場合はfalse
423 public boolean saveNetConfig(JsComposition<?> root){
424 boolean result = saveJson(NETCONFIG_FILE, root);
431 * @return 書き込まなかったもしくは書き込めなかった場合はfalse
433 public boolean saveTalkConfig(JsComposition<?> root){
434 boolean result = saveJson(TALKCONFIG_FILE, root);