    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"  , … } ,                     １レコード目
    042 *   { "カラム1":"値1"  ,  "カラム2":"値2"  , … } ,                     ２レコード目
    043 *    ・・・・
    044 *   { "カラム1":"値1"  ,  "カラム2":"値2"  , … }                               Ｎレコード目
    045 * ]
    046 *
    047 * writeTableParamタグで、key="JsonName" value="パラメータ名" を指定すると、
    048 * JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する事が可能です。
    049 *
    050 * {
    051 * パラメータ名:[
    052 *   { "カラム1":"値1"  ,  "カラム2":"値2"  , … } ,                     １レコード目
    053 *   { "カラム1":"値1"  ,  "カラム2":"値2"  , … } ,                     ２レコード目
    054 *    ・・・・
    055 *   { "カラム1":"値1"  ,  "カラム2":"値2"  , … }                               Ｎレコード目
    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 = "5.6.6.1 (2013/07/12)" ;
    073
    074        // 5.6.6.1 (2013/07/12) keys の整合性チェックを行います。
    075        private static final Map<String,String> keysMap = new LinkedHashMap<String,String>();
    076
    077        static {
    078                keysMap.put( "JSONNAME"         , "JSON形式で、配列をオブジェクトとしてまとめる場合に使う"                                       );
    079                keysMap.put( "LOWERCASE"        , "カラム名(=パラメータ名)を小文字にする場合、true をセット(初期値:false)" );
    080        }
    081
    082        private String  jsonName    = null;             // JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する場合に使う。
    083        private boolean toLowerCase = false;    // カラム名(=パラメータ名)を小文字にする場合、true にセットします。初期値は大文字のまま。
    084
    085        /**
    086         * DBTableModel から データを作成して,PrintWriter に書き出します。
    087         *
    088         * @param       writer PrintWriterオブジェクト
    089         */
    090        @Override
    091        public void writeDBTable( final PrintWriter writer )  {
    092                super.setHeaderSequence( "D" );
    093                super.writeDBTable( writer );
    094        }
    095
    096        /**
    097         * PrintWriter に DBTableModelのテーブル情報を書き込みます。
    098         *
    099         * 出力のXML形式は、ORACLE XDK での出力ファイルと同じ形式ですので、直接データベースに
    100         * 登録することができます。
    101         *
    102         * @og.rev 5.6.0.3 (2012/01/24) JSON形式のフォーマットを作成します。
    103         * @og.rev 5.6.1.2 (2013/02/22) jsonName もダブルクオートで囲う。
    104         *
    105         * @param       table  DBTableModelオブジェクト
    106         * @param       writer PrintWriterオブジェクト
    107         */
    108        @Override
    109        protected void writeData( final DBTableModel table,final PrintWriter writer ) {
    110                int numberOfRows =  table.getRowCount();
    111
    112                String[] names = table.getNames();
    113                if( toLowerCase ) {
    114                        for( int i=0; i<names.length; i++ ) {
    115//                              names[i] = names[i].toLowerCase();                                      5.6.6.1 (2013/07/12)
    116                                names[i] = names[i].toLowerCase(Locale.JAPAN);
    117                        }
    118                }
    119
    120                if( jsonName != null ) {
    121                        writer.println( "{" );
    122                        writer.print( "\"" );                   // 5.6.1.2 (2013/02/22) jsonName もダブルクオートで囲う。
    123                        writer.print( jsonName );
    124                        writer.print( "\":" );                  // 5.6.1.2 (2013/02/22) jsonName もダブルクオートで囲う。
    125                }
    126
    127                writer.println( "[" );
    128
    129                for( int row=0; row<numberOfRows; row++ ) {
    130                        if( row > 0 ) { writer.print( "," ); }                       // 最初以後の連結は、, を使う
    131                        writer.print( "{" );
    132                        for( int i=0; i<numberOfColumns; i++ ) {
    133                                int clm = clmNo[i];
    134                                String val = table.getValue(row,clm);
    135                                // \(バックスラッシュ) と "(ダブルクオート)のエスケープ
    136                                if( val.contains( "\\" ) || val.contains( "\"" ) ) {
    137                                        StringBuilder sb = new StringBuilder();
    138                                        for( int j=0; j<val.length(); j++ ) {
    139                                                char ch = val.charAt( j );
    140                                                if( ch == '\\' || ch == '\"' ) { sb.append( '\\' ); }
    141                                                sb.append( ch );
    142                                        }
    143                                        val = sb.toString();
    144                                }
    145
    146                                if( i > 0 ) { writer.print( "," ); }         // 最初以後の連結は、, を使う
    147                                writer.print( '"' );
    148                                writer.print( names[clm] );
    149                                writer.print( "\":\"" );
    150                                writer.print( val );
    151                                writer.print( '"' );
    152                        }
    153                        writer.println( "}" );
    154                }
    155
    156                writer.println( "]" );
    157
    158                if( jsonName != null ) {
    159                        writer.println( "}" );
    160                }
    161        }
    162
    163        /**
    164         * パラメーターリストをセットします。
    165         * JSONのパラメータ名を指定します。
    166         * 引数が、null の場合は、何もしません。
    167         *
    168         * @og.rev 5.6.0.3 (2012/01/24) JSONのパラメータ名を指定します。
    169         * @og.rev 5.6.6.1 (2013/07/12) keys の整合性チェックを行います。
    170         *
    171         * @param       listParam       HybsEntryリスト
    172         */
    173        @Override
    174        public void setParam( final List<HybsEntry> listParam ) {
    175                if( listParam != null && ! listParam.isEmpty() ) {
    176                        for( HybsEntry entry : listParam ) {
    177                                String key = entry.getKey() ;           // 5.6.6.1 (2013/07/12) keys の整合性チェック
    178                                checkParam( key , keysMap );
    179
    180                                String val = entry.getValue() ;         // 5.6.6.1 (2013/07/12) val を先に取得
    181                                if( val != null && val.length() > 0 ) {
    182                                        // JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する場合に使う。
    183                                        if( "JsonName".equalsIgnoreCase( key ) ) {
    184                                                jsonName = val ;
    185                                        }
    186                                        // カラム名(=パラメータ名)を小文字にする場合、true にセットします。初期値はfalse:大文字のまま。
    187                                        else if( "LowerCase".equalsIgnoreCase( key ) ) {
    188                                                toLowerCase = Boolean.parseBoolean( val );
    189                                        }
    190                                }
    191
    192//                              // JSON形式で、配列をオブジェクトとしてまとめるパラメータを指定する場合に使う。
    193//                              if( "JsonName".equalsIgnoreCase( entry.getKey() ) ) {
    194//                                      jsonName = entry.getValue();
    195//                              }
    196//                              // カラム名(=パラメータ名)を小文字にする場合、true にセットします。初期値は大文字のまま。
    197//                              if( "LowerCase".equalsIgnoreCase( entry.getKey() ) ) {
    198//                                      toLowerCase = true;
    199//                              }
    200                        }
    201                }
    202        }
    203}