001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.plugin.io; 017 018import java.io.PrintWriter; 019import java.util.List; 020import java.util.Locale; 021import java.util.Map ; 022import java.util.LinkedHashMap ; 023 024import org.opengion.fukurou.util.HybsEntry; 025import org.opengion.hayabusa.db.DBTableModel; 026 027/** 028 * TableWriter をJSON形式で出力する為の実装クラスです。 029 * DefaultTableWriter を継承していますので,ラベル,名前,データの出力部のみ 030 * オーバーライドして,JSON形式ファイルの出力機能を実現しています。 031 * 032 * 出力のJSON形式(JavaScript Object Notation)は、JavaScriptにおける 033 * オブジェクトの表記法をベースとした軽量なデータ記述言語です。 034 * このクラスでは、基本的にはすべてを文字列として処理しますので、 035 * 数字や、true,false も、ダブルコーテーションでくくることになります。 036 * ただし、null の場合は、null 表記になりますが、通常 空文字 "" になる場合もあります。 037 * 1レコードのみの場合でも、配列要素として取り扱います。 038 * UTF-8 でエンコードし、MIMEタイプはapplication/json、拡張子はjson とするのが一般的です。 039 * 040 * [ 041 * { "カラム1":"値1" , "カラム2":"値2" , … } , 1レコード目 042 * { "カラム1":"値1" , "カラム2":"値2" , … } , 2レコード目 043 * ・・・・ 044 * { "カラム1":"値1" , "カラム2":"値2" , … } Nレコード目 045 * ] 046 * 047 * writeTableParamタグで、key="JsonName" value="パラメータ名" を指定すると、 048 * JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する事が可能です。 049 * 050 * { 051 * パラメータ名:[ 052 * { "カラム1":"値1" , "カラム2":"値2" , … } , 1レコード目 053 * { "カラム1":"値1" , "カラム2":"値2" , … } , 2レコード目 054 * ・・・・ 055 * { "カラム1":"値1" , "カラム2":"値2" , … } Nレコード目 056 * ] 057 * } 058 * 059 * writeTableParamタグで、key="LowerCase" value="true" を指定すると、 060 * すべてのカラムを小文字で出力します。(データ受信側の都合を配慮) 061 * 初期値は、false なので、基本的に大文字になります。 062 * 063 * @og.rev 5.6.0.3 (2012/01/24) 新規作成 064 * @og.group ファイル出力 065 * 066 * @version 4.0 067 * @author Kazuhiko Hasegawa 068 * @since JDK5.0, 069 */ 070public class TableWriter_JSON extends TableWriter_Default { 071 /** このプログラムのVERSION文字列を設定します。 {@value} */ 072 private static final String VERSION = "6.4.2.0 (2016/01/29)" ; 073 074 // 5.6.6.1 (2013/07/12) keys の整合性チェックを行います。 075 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 076 private static final Map<String,String> KEYS_MAP = new LinkedHashMap<>(); 077 static { 078 KEYS_MAP.put( "JSONNAME" , "JSON形式で、配列をオブジェクトとしてまとめる場合に使う" ); 079 KEYS_MAP.put( "LOWERCASE" , "カラム名(=パラメータ名)を小文字にする場合、true をセット(初期値:false)" ); 080 } 081 082 private String jsonName ; // JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する場合に使う。 083 private boolean toLowerCase ; // カラム名(=パラメータ名)を小文字にする場合、true にセットします。初期値は大文字のまま。 084 085 /** 086 * デフォルトコンストラクター 087 * 088 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor. 089 */ 090 public TableWriter_JSON() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 091 092 /** 093 * DBTableModel から データを作成して,PrintWriter に書き出します。 094 * 095 * @param writer PrintWriterオブジェクト 096 */ 097 @Override 098 public void writeDBTable( final PrintWriter writer ) { 099 super.setHeaderSequence( "D" ); 100 super.writeDBTable( writer ); 101 } 102 103 /** 104 * PrintWriter に DBTableModelのテーブル情報を書き込みます。 105 * 106 * 出力のXML形式は、ORACLE XDK での出力ファイルと同じ形式ですので、直接データベースに 107 * 登録することができます。 108 * 109 * @og.rev 5.6.0.3 (2012/01/24) JSON形式のフォーマットを作成します。 110 * @og.rev 5.6.1.2 (2013/02/22) jsonName もダブルクオートで囲う。 111 * @og.rev 6.0.1.2 (2014/08/08) カラム飛ばしできる機能を追加 112 * 113 * @param table DBTableModelオブジェクト 114 * @param writer PrintWriterオブジェクト 115 */ 116 @Override 117 protected void writeData( final DBTableModel table,final PrintWriter writer ) { 118 final int numberOfRows = table.getRowCount(); 119 120 String[] names = table.getNames(); 121 if( toLowerCase ) { 122 for( int i=0; i<names.length; i++ ) { 123 names[i] = names[i].toLowerCase(Locale.JAPAN); 124 } 125 } 126 127 if( jsonName != null ) { 128 writer.println( "{" ); 129 writer.print( "\"" ); // 5.6.1.2 (2013/02/22) jsonName もダブルクオートで囲う。 130 writer.print( jsonName ); 131 writer.print( "\":" ); // 5.6.1.2 (2013/02/22) jsonName もダブルクオートで囲う。 132 } 133 134 writer.println( "[" ); 135 136 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); // 6.1.0.0 (2014/12/26) refactoring 137 for( int row=0; row<numberOfRows; row++ ) { 138 if( row > 0 ) { writer.print( "," ); } // 最初以後の連結は、, を使う 139 writer.print( "{" ); 140 for( int i=0; i<numberOfColumns; i++ ) { 141 if( i > 0 ) { writer.print( "," ); } // 最初以後の連結は、, を使う 142 final int clm = clmNo[i]; 143 if( clm < 0 ) { continue; } // 6.0.1.2 (2014/08/08) カラム飛ばし 144 145 String val = table.getValue(row,clm); 146 // \(バックスラッシュ) と "(ダブルクオート)のエスケープ 147 if( val.contains( "\\" ) || val.contains( "\"" ) ) { 148 buf.setLength(0); 149 for( int j=0; j<val.length(); j++ ) { 150 final char ch = val.charAt( j ); 151 if( ch == '\\' || ch == '\"' ) { buf.append( '\\' ); } 152 buf.append( ch ); 153 } 154 val = buf.toString(); 155 } 156 157 writer.print( '"' ); 158 writer.print( names[clm] ); 159 writer.print( "\":\"" ); 160 writer.print( val ); 161 writer.print( '"' ); 162 } 163 writer.println( "}" ); 164 } 165 166 writer.println( "]" ); 167 168 if( jsonName != null ) { 169 writer.println( "}" ); 170 } 171 } 172 173 /** 174 * パラメーターリストをセットします。 175 * JSONのパラメータ名を指定します。 176 * 引数が、null の場合は、何もしません。 177 * 178 * @og.rev 5.6.0.3 (2012/01/24) JSONのパラメータ名を指定します。 179 * @og.rev 5.6.6.1 (2013/07/12) keys の整合性チェックを行います。 180 * 181 * @param listParam HybsEntryリスト 182 */ 183 @Override 184 public void setParam( final List<HybsEntry> listParam ) { 185 if( listParam != null && ! listParam.isEmpty() ) { 186 for( final HybsEntry entry : listParam ) { 187 final String key = entry.getKey() ; // 5.6.6.1 (2013/07/12) keys の整合性チェック 188 checkParam( key , KEYS_MAP ); 189 190 final String val = entry.getValue() ; // 5.6.6.1 (2013/07/12) val を先に取得 191 if( val != null && val.length() > 0 ) { 192 // JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する場合に使う。 193 if( "JsonName".equalsIgnoreCase( key ) ) { 194 jsonName = val ; 195 } 196 // カラム名(=パラメータ名)を小文字にする場合、true にセットします。初期値はfalse:大文字のまま。 197 else if( "LowerCase".equalsIgnoreCase( key ) ) { 198 toLowerCase = Boolean.parseBoolean( val ); 199 } 200 } 201 } 202 } 203 } 204}