View Javadoc
1 /*** 2 * Copyright (c) 2005, CodeStreet LLC. All rights reserved. 3 * <p> 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * <p> 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. Redistributions in binary 9 * form must reproduce the above copyright notice, this list of conditions and 10 * the following disclaimer in the documentation and/or other materials provided 11 * with the distribution. Neither the name of CodeStreet LLC. nor the names of 12 * its contributors may be used to endorse or promote products derived from this 13 * software without specific prior written permission. 14 * <p> 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * <p> 27 */ 28 29 package com.codestreet.messageforge; 30 31 import java.util.Date; 32 import java.sql.Timestamp; 33 import java.util.Iterator; 34 import java.util.Map; 35 import java.util.HashMap; 36 37 import java.lang.reflect.*; 38 import java.math.BigDecimal; 39 40 import com.tibco.tibrv.*; 41 42 /*** 43 * Converter class for (Java) Beans. 44 * <p> 45 * A bean must satisfy the following requirements: it must have a no-arg 46 * constructor, all properties that it wishes to be marshalled must have public 47 * get/set methods, the get and set methods must follow the design pattern 48 * getXXX() or GetXXX()and setXXX() or SetXXX(), and the set methods must take 49 * one arg. 50 * </p> 51 * <p> 52 * Bean properties can primitive types (e.g. int), wrappers of primitive types 53 * (e.g. Integer), arrays of primitives (e.g. int[]), arrays of primitive 54 * wrappers (e.g. Integer[]), String, Date, BigDecimal,, String[], Date[], 55 * BigDecimal[], nested beans and arrays of nested beans. 56 * </p> 57 * <p> 58 * 59 * @author <a href="mailto:jawaid.hakim@codestreet.com">jawaid.hakim </a> 60 */ 61 public abstract class ConverterBeanAndTibrv extends Converter 62 { 63 /*** 64 * Marshal a bean into a TIBCO Rendezvous message. 65 * 66 * @param bean 67 * Bean. 68 * @return Marshalled bean. 69 * @throws ConverterException 70 */ 71 public static TibrvMsg marshal(Object bean) throws ConverterException 72 { 73 try 74 { 75 Class beanClass = bean.getClass(); 76 RBeanInfo beanInfo = BeanFactory.createBeanInfo( 77 beanClass.getName(), beanClass); 78 79 TibrvMsg nestedMsg = new TibrvMsg(); 80 nestedMsg.add(BEANNAME_FIELD, getBeanClassName(beanInfo.getName())); 81 82 for (Iterator getters = beanInfo.getGetters().entrySet().iterator(); getters 83 .hasNext();) 84 { 85 Map.Entry entry = (Map.Entry) getters.next(); 86 Method method = (Method) entry.getValue(); 87 Object val = method.invoke(bean, EMPTY_PARAMS); 88 if (val != null) 89 { 90 String fldName = (String) entry.getKey(); 91 Class valType = val.getClass(); 92 if (valType.equals(String.class)) 93 { 94 nestedMsg.add(fldName, val.toString()); 95 } 96 else if (isPrimitiveWrapperType(valType)) 97 { 98 nestedMsg.add(fldName, val); 99 } 100 else if (valType.equals(BigDecimal.class)) 101 { 102 nestedMsg.add(fldName, Converter 103 .getBigDecimalFormatter().format(val)); 104 } 105 else if (valType.equals(Timestamp.class)) 106 { 107 Timestamp realVal = (Timestamp) val; 108 nestedMsg.add(fldName, new Date(realVal.getTime())); 109 } 110 else if (Date.class.isAssignableFrom(valType)) 111 { 112 String sVal = RDateFormat.getInstance().format( 113 (Date) val); 114 nestedMsg.add(fldName, sVal); 115 } 116 else if (valType.isArray()) 117 { 118 int len = Array.getLength(val); 119 Class arrayType = val.getClass(); 120 if (isPrimitiveArray(arrayType) 121 || isPrimitiveWrapperArray(arrayType)) 122 { 123 nestedMsg.add(fldName, val); 124 continue; 125 } 126 TibrvMsg arrayMsg = new TibrvMsg(); 127 int realLen = 0; 128 for (int i = 0; i < len; ++i) 129 { 130 Object elem = Array.get(val, i); 131 if (elem != null) 132 { 133 String index = String.valueOf(i); 134 if (elem.getClass().equals(String.class)) 135 { 136 arrayMsg.add(index, elem); 137 } 138 else if (valType.equals(BigDecimal.class)) 139 { 140 arrayMsg.add(index, Converter 141 .getBigDecimalFormatter().format( 142 elem)); 143 } 144 else if (elem.getClass() 145 .equals(Timestamp.class)) 146 { 147 Timestamp realVal = (Timestamp) elem; 148 arrayMsg.add(index, new Date(realVal 149 .getTime())); 150 } 151 else if (Date.class.isAssignableFrom(elem 152 .getClass())) 153 { 154 arrayMsg.add(index, RDateFormat 155 .getInstance().format((Date) elem)); 156 } 157 else 158 { 159 // TODO: assumes that this is a bean 160 if (realLen == 0) 161 arrayMsg.add(String.valueOf(realLen), 162 marshal(elem)); 163 } 164 ++realLen; 165 } 166 } 167 arrayMsg.add("length", realLen); 168 nestedMsg.add(fldName, arrayMsg); 169 } 170 else if (val instanceof TibrvMsg) 171 { 172 nestedMsg.add(fldName, val); 173 } 174 else if (val instanceof java.util.Collection) 175 { 176 // TODO: check why User does not lazy load collections 177 // throw new ConverterException("Cannot marshal 178 // collection classes"); 179 } 180 else 181 { 182 // Handle everything else like a bean 183 nestedMsg.add(fldName, marshal(val)); 184 } 185 } 186 } 187 188 return nestedMsg; 189 } 190 catch (Exception ex) 191 { 192 throw new ConverterException(ex); 193 } 194 } 195 196 /*** 197 * Unmarshal a bean from a TIBCO Rendezvous message. 198 * 199 * @param source 200 * TIBCO Rendezvous message. 201 * @return New bean instance. 202 * @throws ConverterException 203 */ 204 public static Object unmarshal(TibrvMsg source) throws ConverterException 205 { 206 try 207 { 208 String beanName = (String) source.get(BEANNAME_FIELD); 209 if (beanName == null) 210 throw new ConverterException("Bean type not found"); 211 212 // Instantiate bean 213 String fullName = RMsgFactoryImpl.getInstance() 214 .getFullBeanFieldName(beanName); 215 if (fullName == null) 216 throw new ConverterException("Qualified bean name not found"); 217 218 return unmarshal(source, beanName, fullName); 219 } 220 catch (Exception ex) 221 { 222 throw new ConverterException(ex); 223 } 224 } 225 226 /*** 227 * Unmarshal a bean from a TIBCO Rendezvous message. 228 * 229 * @param source 230 * TIBCO Rendezvous message. 231 * @param beanName 232 * Short name of bean. 233 * @param fullName 234 * Full name of bean (includes the package). 235 * @return New bean instance. 236 * @throws ConverterException 237 */ 238 public static Object unmarshal(TibrvMsg source, String beanName, 239 String fullName) throws ConverterException 240 { 241 try 242 { 243 Object bean = Class.forName(fullName).newInstance(); 244 245 // Set bean properties 246 RBeanInfo beanInfo = BeanFactory.createBeanInfo(beanName, bean 247 .getClass()); 248 for (Iterator setters = beanInfo.getSetters().values().iterator(); setters 249 .hasNext();) 250 { 251 Method method = (Method) setters.next(); 252 String fldName = method.getName().substring(3); 253 TibrvMsgField fld = source.getField(fldName); 254 if (fld != null) 255 { 256 Object val = fld.data; 257 Class[] methodParameters = method.getParameterTypes(); 258 Class valType = methodParameters[0]; 259 if (valType.equals(String.class)) 260 { 261 Object[] parameters = { val.toString() }; 262 method.invoke(bean, parameters); 263 } 264 else if (isPrimitiveWrapperType(valType)) 265 { 266 Object[] parameters = { val }; 267 method.invoke(bean, parameters); 268 } 269 else if (valType.equals(BigDecimal.class)) 270 { 271 Object[] parameters = { new BigDecimal(val.toString()) }; 272 method.invoke(bean, parameters); 273 } 274 else if (valType.equals(Timestamp.class)) 275 { 276 Object[] parameters = { new Timestamp(((Date)val).getTime()) }; 277 method.invoke(bean, parameters); 278 } 279 else if (Date.class.isAssignableFrom(valType)) 280 { 281 Object[] parameters = { RDateFormat.getInstance() 282 .parse(val.toString()) }; 283 method.invoke(bean, parameters); 284 } 285 else if (valType.isArray()) 286 { 287 if (isPrimitiveArray(valType)) 288 { 289 Object[] parameters = { val }; 290 method.invoke(bean, parameters); 291 } 292 else if (isPrimitiveWrapperArray(valType)) 293 { 294 Object[] parameters = { val }; 295 method.invoke(bean, parameters); 296 } 297 else 298 { 299 // BigDecimal, String, Date, or Bean array 300 TibrvMsg arrayMsg = (TibrvMsg) val; 301 int len = arrayMsg.getInt("length", 0); 302 String arrayClsName = valType.getName(); 303 Object newArray = Array.newInstance(Class 304 .forName(arrayClsName.substring(2, 305 arrayClsName.indexOf(';'))), len); 306 for (int i = 0; i < len; ++i) 307 { 308 Object elem = arrayMsg.get(String.valueOf(i)); 309 if (arrayClsName.equals("[Ljava.lang.String;")) 310 { 311 Array.set(newArray, i, elem); 312 } 313 else if (arrayClsName 314 .equals("[Ljava.math.BigDecimal;")) 315 { 316 Array.set(newArray, i, new BigDecimal(elem 317 .toString())); 318 } 319 else if (arrayClsName 320 .equals("[Ljava.util.Date;")) 321 { 322 Array.set(newArray, i, elem); 323 } 324 else if (arrayClsName 325 .equals("[Ljava.sql.Timestamp;")) 326 { 327 Array 328 .set( 329 newArray, 330 i, new Timestamp(((Date)elem).getTime())); 331 } 332 else if (elem instanceof TibrvMsg) 333 { 334 // TODO: assumes that this is a bean 335 Array.set(newArray, i, 336 unmarshal((TibrvMsg) elem)); 337 } 338 } 339 Object[] parameters = { newArray }; 340 method.invoke(bean, parameters); 341 } 342 } 343 else if (val instanceof TibrvMsg) 344 { 345 TibrvMsg msg = (TibrvMsg) val; 346 String beanFieldName = (String) msg.get(BEANNAME_FIELD); 347 if (beanFieldName != null) 348 { 349 Object[] parameters = { unmarshal(msg) }; 350 method.invoke(bean, parameters); 351 } 352 else 353 { 354 Object[] parameters = { msg }; 355 method.invoke(bean, parameters); 356 } 357 } 358 else 359 { 360 Object[] parameters = { val }; 361 method.invoke(bean, parameters); 362 } 363 } 364 } 365 return bean; 366 } 367 catch (Exception ex) 368 { 369 throw new ConverterException(ex); 370 } 371 } 372 373 /*** 374 * Get the unqualified name of the bean class. 375 * 376 * @param fullName 377 * Fully qualified name of the bean class. This can also be the 378 * unqualified name. 379 * @return Unqualified name of the bean class. 380 */ 381 private static String getBeanClassName(String fullName) 382 { 383 int index = fullName.lastIndexOf("."); 384 return fullName.substring(index + 1); 385 } 386 387 /*** 388 * Determine if a bean class is a primitive wrapper type. A primitive 389 * wrapper type can be directly inserted into a <tt>TibrvMsg</tt>. 390 * 391 * @param cls 392 * Bean class. 393 * @return Returns <tt>true</tt> if the bean class is a supported 394 * non-primitive type. Otherwise, returns <tt>false</tt>. 395 */ 396 private static boolean isPrimitiveWrapperType(Class cls) 397 { 398 String name = cls.getName(); 399 return primitiveTypes.containsKey(name) 400 || primitiveWrapperTypes.containsKey(name); 401 } 402 403 /*** 404 * Determine if a bean attribute is an array of <tt>primitive</tt> types. 405 * A primitive array type can be directly inserted into a <tt>TibrvMsg</tt>. 406 * 407 * @param cls 408 * Bean class. 409 * @return Returns <tt>true</tt> if the bean class is an array of 410 * <tt>primitive</tt> types. Otherwise, returns <tt>false</tt>. 411 */ 412 private static boolean isPrimitiveArray(Class cls) 413 { 414 String name = cls.getName(); 415 return primitiveTypesArray.containsKey(name); 416 } 417 418 /*** 419 * Determine if a bean class is an array of primitive wrapper type. A 420 * primitive wrapper array type can be directly inserted into a 421 * <tt>TibrvMsg</tt>. 422 * 423 * @param cls 424 * Bean class. 425 * @return Returns <tt>true</tt> if the bean class is an array of 426 * primitive wrapper types. Otherwise, returns <tt>false</tt>. 427 */ 428 private static boolean isPrimitiveWrapperArray(Class cls) 429 { 430 String name = cls.getName(); 431 return primitiveWrapperTypesArray.containsKey(name); 432 } 433 434 private static Map primitiveTypes = new HashMap(); 435 436 private static Map primitiveWrapperTypes = new HashMap(); 437 438 private static Map primitiveWrapperTypesArray = new HashMap(); 439 440 private static Map primitiveTypesArray = new HashMap(); 441 442 private static final Object[] EMPTY_PARAMS = {}; 443 444 private static final String BEANNAME_FIELD = "csmbeanname__"; 445 446 static 447 { 448 primitiveTypes.put("short", ""); 449 primitiveTypes.put("int", ""); 450 primitiveTypes.put("long", ""); 451 primitiveTypes.put("float", ""); 452 primitiveTypes.put("double", ""); 453 primitiveTypes.put("byte", ""); 454 primitiveTypes.put("boolean", ""); 455 primitiveTypes.put("char", ""); 456 457 primitiveWrapperTypes.put("java.lang.Short", ""); 458 primitiveWrapperTypes.put("java.lang.Integer", ""); 459 primitiveWrapperTypes.put("java.lang.Long", ""); 460 primitiveWrapperTypes.put("java.lang.Float", ""); 461 primitiveWrapperTypes.put("java.lang.Double", ""); 462 primitiveWrapperTypes.put("java.lang.Byte", ""); 463 primitiveWrapperTypes.put("java.lang.Boolean", ""); 464 primitiveWrapperTypes.put("java.lang.Char", ""); 465 466 primitiveTypesArray.put("[S", ""); 467 primitiveTypesArray.put("[I", ""); 468 primitiveTypesArray.put("[L", ""); 469 primitiveTypesArray.put("[F", ""); 470 primitiveTypesArray.put("[D", ""); 471 primitiveTypesArray.put("[B", ""); 472 primitiveTypesArray.put("[Z", ""); 473 primitiveTypesArray.put("[C", ""); 474 475 primitiveWrapperTypesArray.put("[Ljava.lang.Short;", ""); 476 primitiveWrapperTypesArray.put("[Ljava.lang.Integer;", ""); 477 primitiveWrapperTypesArray.put("[Ljava.lang.Long;", ""); 478 primitiveWrapperTypesArray.put("[Ljava.lang.Float;", ""); 479 primitiveWrapperTypesArray.put("[Ljava.lang.Double;", ""); 480 primitiveWrapperTypesArray.put("[Ljava.lang.Byte;", ""); 481 primitiveWrapperTypesArray.put("[Ljava.lang.Boolean;", ""); 482 primitiveWrapperTypesArray.put("[Ljava.lang.Char;", ""); 483 } 484 }

This page was automatically generated by Maven