001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.dto.cognos; 014 015import java.util.*; 016 017import org.apache.juneau.*; 018import org.apache.juneau.annotation.*; 019import org.apache.juneau.xml.annotation.*; 020 021/** 022 * Represents a Cognos dataset. 023 * 024 * <p> 025 * When serialized to XML, creates the following construct (example pulled from <c>AddressBookResource</c>): 026 * <p class='bcode w800'> 027 * <xt><?xml</xt> <xa>version</xa>=<xs>'1.0'</xs> <xa>encoding</xa>=<xs>'UTF-8'</xs><xt>?></xt> 028 * <xt><c:dataset <xa>xmlns:c</xa>=<xs>'http://developer.cognos.com/schemas/xmldata/1/'</xs>></xt> 029 * <xt><c:metadata></xt> 030 * <xt><c:item</xt> <xa>name</xa>=<xs>'name'</xs> <xa>type</xa>=<xs>'xs:String'</xs> 031 * <xa>length</xa>=<xs>'255'</xs><xt>/></xt> 032 * <xt><c:item</xt> <xa>name</xa>=<xs>'age'</xs> <xa>type</xa>=<xs>'xs:int'</xs><xt>/></xt> 033 * <xt><c:item</xt> <xa>name</xa>=<xs>'numAddresses'</xs> <xa>type</xa>=<xs>'xs:int'</xs><xt>/></xt> 034 * <xt></c:metadata></xt> 035 * <xt><c:data></xt> 036 * <xt><c:row></xt> 037 * <xt><c:value></xt>Barack Obama<xt></c:value></xt> 038 * <xt><c:value></xt>52<xt></c:value></xt> 039 * <xt><c:value></xt>2<xt></c:value></xt> 040 * <xt></c:row></xt> 041 * <xt><c:row></xt> 042 * <xt><c:value></xt>George Walker Bush<xt></c:value></xt> 043 * <xt><c:value></xt>67<xt></c:value></xt> 044 * <xt><c:value></xt>2<xt></c:value></xt> 045 * <xt></c:row></xt> 046 * <xt></c:data></xt> 047 * <xt></c:dataset></xt> 048 * </p> 049 * 050 * <p> 051 * Only 2-dimensional POJOs (arrays or collections of maps or beans) can be serialized to Cognos. 052 * 053 * <h5 class='section'>Example:</h5> 054 * 055 * The construct shown above is a serialized <c>AddressBook</c> object which is a subclass of 056 * <c>LinkedList<Person></c>. 057 * The code for generating the XML is as follows... 058 * <p class='bcode w800'> 059 * Column[] items = { 060 * <jk>new</jk> Column(<js>"name"</js>, <js>"xs:String"</js>, 255), 061 * <jk>new</jk> Column(<js>"age"</js>, <js>"xs:int"</js>), 062 * <jk>new</jk> Column(<js>"numAddresses"</js>, <js>"xs:int"</js>) 063 * .addPojoSwap( 064 * <jk>new</jk> PojoSwap<Person,Integer>() { 065 * <ja>@Override</ja> 066 * <jk>public</jk> Integer swap(Person p) { 067 * <jk>return</jk> p.<jf>addresses</jf>.size(); 068 * } 069 * } 070 * ) 071 * }; 072 * 073 * DataSet ds = <jk>new</jk> DataSet(items, <jsf>addressBook</jsf>, BeanContext.<jsf>DEFAULT</jsf>); 074 * 075 * String xml = XmlSerializer.<jsf>DEFAULT_SQ</jsf>.serialize(ds); 076 * </p> 077 */ 078@SuppressWarnings("unchecked") 079@Bean(typeName="dataset", bpi="metadata,data") 080public class DataSet { 081 082 private Column[] metaData; 083 private List<Row> data; 084 085 /** Bean constructor. */ 086 public DataSet() {} 087 088 /** 089 * Constructor. 090 * 091 * @param columns The meta-data that represents the columns in the dataset. 092 * @param o 093 * The POJO being serialized to Cognos. 094 * Must be an array/collection of beans/maps. 095 * @param session The bean session used to convert POJOs to strings. 096 * @throws Exception An error occurred trying to serialize the POJO. 097 */ 098 public DataSet(Column[] columns, Object o, BeanSession session) throws Exception { 099 metaData = columns; 100 data = new LinkedList<>(); 101 if (o != null) { 102 if (o.getClass().isArray()) 103 o = Arrays.asList((Object[])o); 104 if (o instanceof Collection) { 105 Collection<?> c = (Collection<?>)o; 106 for (Object o2 : c) { 107 Row r = new Row(); 108 Map<?,?> m = null; 109 if (o2 instanceof Map) 110 m = (Map<?,?>)o2; 111 else 112 m = session.toBeanMap(o2); 113 for (Column col : columns) { 114 Object v; 115 if (col.pojoSwap != null) 116 v = col.pojoSwap.swap(session, o2); 117 else 118 v = m.get(col.getName()); 119 r.add(v == null ? null : v.toString()); 120 } 121 data.add(r); 122 } 123 } 124 } 125 } 126 127 /** 128 * Represents a row of data. 129 * 130 * <p> 131 * When serialized to XML, creates the following construct (example pulled from <c>AddressBookResource</c>): 132 * <p class='bcode w800'> 133 * <xt><row></xt> 134 * <xt><value></xt>Barack Obama<xt></value></xt> 135 * <xt><value></xt>52<xt></value></xt> 136 * <xt><value></xt>2<xt></value></xt> 137 * <xt></row></xt> 138 * </p> 139 */ 140 @Bean(typeName="row") 141 public static final class Row { 142 private List<String> values = new LinkedList<>(); 143 144 void add(String value) { 145 values.add(value); 146 } 147 148 /** 149 * Returns the values in this row. 150 * 151 * @return The values in this row. 152 */ 153 @Xml(format=XmlFormat.COLLAPSED, childName="value") 154 public List<String> getValues() { 155 return values; 156 } 157 } 158 159 160 //----------------------------------------------------------------------------------------------------------------- 161 // Bean properties 162 //----------------------------------------------------------------------------------------------------------------- 163 164 /** 165 * Bean property getter: <property>metadata</property>. 166 * 167 * @return The value of the <property>metadata</property> property on this bean, or <jk>null</jk> if it is not set. 168 */ 169 @Beanp("metadata") 170 public Column[] getMetaData() { 171 return metaData; 172 } 173 174 /** 175 * Bean property setter: <property>metadata</property>. 176 * 177 * @param metaData The new value for the <property>metadata</property> property on this bean. 178 * @return This object (for method chaining). 179 */ 180 @Beanp("metadata") 181 public DataSet setMetaData(Column[] metaData) { 182 this.metaData = metaData; 183 return this; 184 } 185 186 /** 187 * Bean property getter: <property>data</property>. 188 * 189 * @return The value of the <property>data</property> property on this bean, or <jk>null</jk> if it is not set. 190 */ 191 @Beanp("data") 192 public List<Row> getData() { 193 return data; 194 } 195 196 /** 197 * Bean property setter: <property>data</property>. 198 * 199 * @param data The new value for the <property>data</property> property on this bean. 200 * @return This object (for method chaining). 201 */ 202 @Beanp("data") 203 public DataSet setData(List<Row> data) { 204 this.data = data; 205 return this; 206 } 207}