001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.transformer.bytecode.cast; 020 021import lucee.commons.lang.ClassException; 022import lucee.commons.lang.ClassUtil; 023import lucee.commons.lang.StringUtil; 024import lucee.transformer.bytecode.BytecodeContext; 025import lucee.transformer.bytecode.BytecodeException; 026import lucee.transformer.bytecode.expression.Expression; 027import lucee.transformer.bytecode.expression.ExpressionBase; 028import lucee.transformer.bytecode.expression.var.Variable; 029import lucee.transformer.bytecode.expression.var.VariableString; 030import lucee.transformer.bytecode.util.Methods_Caster; 031import lucee.transformer.bytecode.util.Types; 032 033import org.objectweb.asm.Type; 034import org.objectweb.asm.commons.GeneratorAdapter; 035import org.objectweb.asm.commons.Method; 036 037/** 038 * cast a Expression to a Double 039 */ 040public final class CastOther extends ExpressionBase implements Cast { 041 // TODO support short type 042 private Expression expr; 043 private String type; 044 private String lcType; 045 046 private CastOther(Expression expr, String type, String lcType) { 047 super(expr.getStart(),expr.getEnd()); 048 this.expr=expr; 049 this.type=type; 050 this.lcType=lcType; 051 052 } 053 054 public static Expression toExpression(Expression expr, String type) { 055 if(type==null) return expr; 056 057 String lcType=StringUtil.toLowerCase(type); 058 switch(lcType.charAt(0)) { 059 case 'a': 060 if("any".equals(lcType)) { 061 return expr; 062 } 063 break; 064 case 'b': 065 if("boolean".equals(type) || "bool".equals(lcType)) return CastBoolean.toExprBoolean(expr); 066 break; 067 case 'd': 068 if("double".equals(type)) return CastDouble.toExprDouble(expr); 069 break; 070 case 'i': 071 if("int".equals(lcType)) return CastInt.toExprInt(expr); 072 case 'n': 073 if("number".equals(lcType) || "numeric".equals(lcType))return CastDouble.toExprDouble(expr); 074 break; 075 case 'o': 076 if("object".equals(lcType)) { 077 return expr; 078 } 079 break; 080 case 's': 081 if("string".equals(lcType)) return CastString.toExprString(expr); 082 //if("string_array".equals(lcType)) return StringArray.toExpr(expr); 083 break; 084 case 'u': 085 if("uuid".equals(lcType)) return CastString.toExprString(expr); 086 break; 087 case 'v': 088 if("variablename".equals(lcType)) return VariableString.toExprString(expr); 089 if("variable_name".equals(lcType)) return VariableString.toExprString(expr); 090 if("variablestring".equals(lcType)) return VariableString.toExprString(expr); 091 if("variable_string".equals(lcType)) return VariableString.toExprString(expr); 092 if("void".equals(lcType)) return expr; 093 break; 094 095 096 097 098 } 099 return new CastOther(expr,type,lcType); 100 } 101 102 // Array toArray(Object) 103 final public static Method TO_ARRAY = new Method("toArray", 104 Types.ARRAY, 105 new Type[]{Types.OBJECT}); 106 107 // String toBase64 (Object); 108 final public static Method TO_BASE64 = new Method("toBase64", 109 Types.STRING, 110 new Type[]{Types.OBJECT}); 111 112 // byte[] toBinary (Object) 113 final public static Method TO_BINARY = new Method("toBinary", 114 Types.BYTE_VALUE_ARRAY, 115 new Type[]{Types.OBJECT}); 116 117 // byte[] toCollection (Object) 118 final public static Method TO_COLLECTION = new Method("toCollection", 119 Types.BYTE_VALUE_ARRAY, 120 new Type[]{Types.OBJECT}); 121 122 // lucee.runtime.Component toComponent (Object) 123 final public static Method TO_COMPONENT = new Method("toComponent", 124 Types.COMPONENT, 125 new Type[]{Types.OBJECT}); 126 127 128 // String toDecimal (Object) 129 final public static Method TO_DECIMAL = new Method("toDecimal", 130 Types.STRING, 131 new Type[]{Types.OBJECT}); 132 133 // lucee.runtime.config.Config getConfig () 134 final public static Method GET_CONFIG = new Method("getConfig", 135 Types.CONFIG_WEB, 136 new Type[]{}); 137 138 //java.util.TimeZone getTimeZone () 139 final public static Method GET_TIMEZONE = new Method("getTimeZone", 140 Types.TIMEZONE, 141 new Type[]{}); 142 143 // Excel toExcel (Object) 144 final public static Method TO_EXCEL = new Method("toExcel", 145 Types.EXCEL, 146 new Type[]{Types.OBJECT}); 147 148 /** 149 * @see lucee.transformer.bytecode.expression.Expression#_writeOut(org.objectweb.asm.commons.GeneratorAdapter, int) 150 */ 151 public Type _writeOut(BytecodeContext bc, int mode) throws BytecodeException { 152//Caster.toDecimal(null); 153 GeneratorAdapter adapter = bc.getAdapter(); 154 char first=lcType.charAt(0); 155 Type rtn; 156 switch(first) { 157 case 'a': 158 if("array".equals(lcType)) { 159 rtn=expr.writeOut(bc,MODE_REF); 160 if(!rtn.equals(Types.ARRAY)) 161 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_ARRAY); 162 return Types.ARRAY; 163 } 164 break; 165 case 'b': 166 if("base64".equals(lcType)) { 167 expr.writeOut(bc,MODE_REF); 168 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BASE64); 169 return Types.STRING; 170 } 171 if("binary".equals(lcType)) { 172 rtn=expr.writeOut(bc,MODE_REF); 173 if(!rtn.equals(Types.BYTE_VALUE_ARRAY)) 174 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BINARY); 175 return Types.BYTE_VALUE_ARRAY; 176 } 177 if("byte".equals(type)) { 178 rtn=expr.writeOut(bc,MODE_VALUE); 179 if(!rtn.equals(Types.BYTE_VALUE)) 180 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE_VALUE[Types.getType(rtn)]); 181 return Types.BYTE_VALUE; 182 } 183 if("byte".equals(lcType)) { 184 rtn=expr.writeOut(bc,MODE_REF); 185 if(!rtn.equals(Types.BYTE)) 186 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE[Types.getType(rtn)]); 187 return Types.BYTE; 188 } 189 if("boolean".equals(lcType)) { 190 return CastBoolean.toExprBoolean(expr).writeOut(bc, MODE_REF); 191 } 192 break; 193 case 'c': 194 if("char".equals(lcType)) { 195 rtn=expr.writeOut(bc,MODE_VALUE); 196 if(!rtn.equals(Types.CHAR)) 197 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHAR_VALUE[Types.getType(rtn)]); 198 return Types.CHAR; 199 } 200 if("character".equals(lcType)) { 201 rtn=expr.writeOut(bc,MODE_REF); 202 if(!rtn.equals(Types.CHARACTER)) 203 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHARACTER[Types.getType(rtn)]); 204 return Types.CHARACTER; 205 } 206 if("collection".equals(lcType)) { 207 rtn=expr.writeOut(bc,MODE_REF); 208 if(!rtn.equals(Types.COLLECTION)) 209 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COLLECTION); 210 return Types.COLLECTION; 211 } 212 if("component".equals(lcType)) { 213 rtn=expr.writeOut(bc,MODE_REF); 214 if(!rtn.equals(Types.COMPONENT)) 215 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_COMPONENT); 216 return Types.COMPONENT; 217 } 218 break; 219 case 'd': 220 if("double".equals(lcType)) { 221 return CastDouble.toExprDouble(expr).writeOut(bc, MODE_REF); 222 } 223 if("date".equals(lcType) || "datetime".equals(lcType)) { 224 // First Arg 225 rtn=expr.writeOut(bc,MODE_REF); 226 if(rtn.equals(Types.DATE_TIME)) return Types.DATE_TIME; 227 228 int type=Types.getType(rtn); 229 230 // Second Arg 231 adapter.loadArg(0); 232 //adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_CONFIG); 233 //adapter.invokeInterface(Types.CONFIG_WEB,GET_TIMEZONE); 234 adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_TIMEZONE); 235 236 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DATE[type]); 237 return Types.DATE_TIME; 238 } 239 if("decimal".equals(lcType)) { 240 rtn=expr.writeOut(bc,MODE_REF); 241 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DECIMAL[Types.getType(rtn)]); 242 return Types.STRING; 243 } 244 break; 245 case 'e': 246 if("excel".equals(type)) { 247 expr.writeOut(bc,MODE_REF); 248 adapter.invokeStatic(Types.EXCEL_UTIL,TO_EXCEL); 249 return Types.EXCEL; 250 } 251 break; 252 case 'f': 253 if("file".equals(lcType)) { 254 rtn=expr.writeOut(bc,MODE_REF); 255 if(!rtn.equals(Types.FILE)) 256 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FILE); 257 return Types.FILE; 258 } 259 if("float".equals(type)) { 260 rtn=expr.writeOut(bc,MODE_VALUE); 261 if(!rtn.equals(Types.FLOAT_VALUE)) 262 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT_VALUE[Types.getType(rtn)]); 263 return Types.FLOAT_VALUE; 264 } 265 if("float".equals(lcType)) { 266 rtn=expr.writeOut(bc,MODE_REF); 267 if(!rtn.equals(Types.FLOAT)) 268 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT[Types.getType(rtn)]); 269 return Types.FLOAT; 270 } 271 break; 272 case 'i': 273 if("int".equals(lcType)) { 274 rtn=expr.writeOut(bc,MODE_VALUE); 275 if(!rtn.equals(Types.INT_VALUE)) 276 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INT_VALUE[Types.getType(rtn)]); 277 return Types.INT_VALUE; 278 } 279 if("integer".equals(lcType)) { 280 rtn=expr.writeOut(bc,MODE_REF); 281 if(!rtn.equals(Types.INTEGER)) 282 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INTEGER[Types.getType(rtn)]); 283 return Types.INTEGER; 284 } 285 if("image".equals(lcType)) { 286 rtn=expr.writeOut(bc,MODE_REF); 287 if(!rtn.equals(Types.IMAGE)) { 288 adapter.loadArg(0); 289 adapter.invokeStatic(Types.IMAGE,Methods_Caster.TO_IMAGE); 290 } 291 return Types.IMAGE; 292 } 293 break; 294 case 'j': 295 296 if("java.lang.boolean".equals(lcType)) { 297 return CastBoolean.toExprBoolean(expr).writeOut(bc, MODE_REF); 298 } 299 if("java.lang.double".equals(lcType)) { 300 return CastDouble.toExprDouble(expr).writeOut(bc, MODE_REF); 301 } 302 if("java.lang.string".equals(lcType)) { 303 return CastString.toExprString(expr).writeOut(bc, MODE_REF); 304 } 305 if("java.lang.stringbuffer".equals(lcType)) { 306 rtn=expr.writeOut(bc,MODE_REF); 307 if(!rtn.equals(Types.STRING_BUFFER)) 308 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRING_BUFFER); 309 return Types.STRING_BUFFER; 310 } 311 if("java.lang.byte".equals(lcType)) { 312 rtn=expr.writeOut(bc,MODE_REF); 313 if(!rtn.equals(Types.BYTE)) 314 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_BYTE[Types.getType(rtn)]); 315 return Types.BYTE; 316 } 317 if("java.lang.character".equals(lcType)) { 318 rtn=expr.writeOut(bc,MODE_REF); 319 if(!rtn.equals(Types.CHARACTER)) 320 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_CHARACTER[Types.getType(rtn)]); 321 return Types.CHARACTER; 322 } 323 if("java.lang.short".equals(lcType)) { 324 rtn=expr.writeOut(bc,MODE_REF); 325 if(!rtn.equals(Types.SHORT)) 326 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT[Types.getType(rtn)]); 327 return Types.SHORT; 328 } 329 if("java.lang.integer".equals(lcType)) { 330 rtn=expr.writeOut(bc,MODE_REF); 331 if(!rtn.equals(Types.INTEGER)) 332 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_INTEGER[Types.getType(rtn)]); 333 return Types.INTEGER; 334 } 335 if("java.lang.long".equals(lcType)) { 336 rtn=expr.writeOut(bc,MODE_REF); 337 if(!rtn.equals(Types.LONG)) 338 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG[Types.getType(rtn)]); 339 return Types.LONG; 340 } 341 if("java.lang.float".equals(lcType)) { 342 rtn=expr.writeOut(bc,MODE_REF); 343 if(!rtn.equals(Types.FLOAT)) 344 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FLOAT[Types.getType(rtn)]); 345 return Types.FLOAT; 346 } 347 if("java.io.file".equals(lcType)) { 348 rtn=expr.writeOut(bc,MODE_REF); 349 if(!rtn.equals(Types.FILE)) 350 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_FILE); 351 return Types.FILE; 352 } 353 if("java.lang.object".equals(lcType)) { 354 return expr.writeOut(bc,MODE_REF); 355 } 356 else if("java.util.date".equals(lcType)) { 357 // First Arg 358 rtn=expr.writeOut(bc,MODE_REF); 359 if(rtn.equals(Types.DATE)) return Types.DATE; 360 if(rtn.equals(Types.DATE_TIME)) return Types.DATE_TIME; 361 362 // Second Arg 363 adapter.loadArg(0); 364 //adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_CONFIG); 365 //adapter.invokeVirtual(Types.CONFIG_WEB,GET_TIMEZONE); 366 adapter.invokeVirtual(Types.PAGE_CONTEXT,GET_TIMEZONE); 367 368 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_DATE[Types.getType(rtn)]); 369 return Types.DATE_TIME; 370 } 371 break; 372 case 'l': 373 if("long".equals(type)) { 374 rtn=expr.writeOut(bc,MODE_VALUE); 375 if(!rtn.equals(Types.LONG_VALUE)) 376 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG_VALUE[Types.getType(rtn)]); 377 return Types.LONG_VALUE; 378 } 379 else if("long".equals(lcType)) { 380 rtn=expr.writeOut(bc,MODE_REF); 381 if(!rtn.equals(Types.LONG)) 382 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_LONG[Types.getType(rtn)]); 383 return Types.LONG; 384 } 385 break; 386 case 'n': 387 if("node".equals(lcType)) { 388 rtn=expr.writeOut(bc,MODE_REF); 389 if(!rtn.equals(Types.NODE)) 390 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NODE); 391 return Types.NODE; 392 } 393 else if("null".equals(lcType)) { 394 expr.writeOut(bc,MODE_REF); 395 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NULL); 396 // TODO gibt es einen null typ? 397 return Types.OBJECT; 398 } 399 break; 400 case 'o': 401 if("object".equals(lcType) || "other".equals(lcType)) { 402 expr.writeOut(bc,MODE_REF); 403 return Types.OBJECT; 404 } 405 break; 406 case 's': 407 if("struct".equals(lcType)) { 408 rtn=expr.writeOut(bc,MODE_REF); 409 if(!rtn.equals(Types.STRUCT)) 410 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRUCT); 411 return Types.STRUCT; 412 } 413 if("short".equals(type)) { 414 rtn=expr.writeOut(bc,MODE_VALUE); 415 if(!rtn.equals(Types.SHORT_VALUE)) 416 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT_VALUE[Types.getType(rtn)]); 417 return Types.SHORT_VALUE; 418 } 419 if("short".equals(lcType)) { 420 rtn=expr.writeOut(bc,MODE_REF); 421 if(!rtn.equals(Types.SHORT)) 422 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_SHORT[Types.getType(rtn)]); 423 return Types.SHORT; 424 } 425 if("stringbuffer".equals(lcType)) { 426 rtn=expr.writeOut(bc,MODE_REF); 427 if(!rtn.equals(Types.STRING_BUFFER)) 428 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_STRING_BUFFER); 429 return Types.STRING_BUFFER; 430 } 431 break; 432 433 case 'x': 434 if("xml".equals(lcType)) { 435 rtn=expr.writeOut(bc,MODE_REF); 436 if(!rtn.equals(Types.NODE)) 437 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_NODE); 438 return Types.NODE; 439 } 440 break; 441 default: 442 if("query".equals(lcType)) { 443 rtn=expr.writeOut(bc,MODE_REF); 444 if(!rtn.equals(Types.QUERY)) 445 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_QUERY); 446 return Types.QUERY; 447 } 448 if("querycolumn".equals(lcType)) { 449 rtn=(expr instanceof Variable)?((Variable)expr).writeOutCollection(bc, mode):expr.writeOut(bc,MODE_REF); 450 if(!rtn.equals(Types.QUERY_COLUMN)) { 451 452 adapter.loadArg(0); 453 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_QUERY_COLUMN); 454 } 455 return Types.QUERY_COLUMN; 456 } 457 else if("timespan".equals(lcType)) { 458 rtn=expr.writeOut(bc,MODE_REF); 459 if(!rtn.equals(Types.TIMESPAN)) 460 adapter.invokeStatic(Types.CASTER,Methods_Caster.TO_TIMESPAN); 461 return Types.TIMESPAN; 462 } 463 } 464 Type t=getType(type); 465 466 expr.writeOut(bc,MODE_REF); 467 adapter.checkCast(t); 468 return t; 469 } 470 471 /* 472 private int writeExprx(BytecodeContext bc) throws TemplateException { 473 return Types.getType(expr.writeOut(bc,MODE_VALUE)); 474 }*/ 475 476 477 478 public static Type getType(String type) throws BytecodeException { 479 if(StringUtil.isEmpty(type)) return Types.OBJECT; 480 481 482 String lcType=StringUtil.toLowerCase(type); 483 switch(lcType.charAt(0)) { 484 case 'a': 485 if("any".equals(lcType)) return Types.OBJECT; 486 if("array".equals(lcType)) return Types.ARRAY; 487 break; 488 case 'b': 489 if("bool".equals(lcType) || "boolean".equals(type)) return Types.BOOLEAN_VALUE; 490 if("boolean".equals(lcType)) return Types.BOOLEAN; 491 if("base64".equals(lcType)) return Types.STRING; 492 493 if("binary".equals(lcType)) return Types.BYTE_VALUE_ARRAY; 494 if("byte".equals(type)) return Types.BYTE_VALUE; 495 if("byte".equals(lcType)) return Types.BYTE; 496 497 break; 498 499 case 'c': 500 if("char".equals(lcType)) return Types.CHAR; 501 if("character".equals(lcType)) return Types.CHARACTER; 502 if("collection".equals(lcType)) return Types.COLLECTION; 503 if("component".equals(lcType)) return Types.COMPONENT; 504 break; 505 506 case 'd': 507 if("double".equals(type)) return Types.DOUBLE_VALUE; 508 if("double".equals(lcType)) return Types.DOUBLE; 509 510 if("date".equals(lcType) || "datetime".equals(lcType))return Types.DATE_TIME; 511 if("decimal".equals(lcType)) return Types.STRING; 512 513 break; 514 515 case 'e': 516 if("excel".equals(lcType)) return Types.EXCEL; 517 break; 518 case 'f': 519 if("file".equals(lcType)) return Types.FILE; 520 if("float".equals(type)) return Types.FLOAT_VALUE; 521 if("float".equals(lcType)) return Types.FLOAT; 522 if("function".equals(lcType)) return Types.UDF; 523 break; 524 525 case 'i': 526 if("image".equals(lcType)) return Types.IMAGE; 527 if("int".equals(lcType)) return Types.INT_VALUE; 528 if("integer".equals(lcType)) return Types.INTEGER; 529 break; 530 531 case 'l': 532 if("long".equals(type)) return Types.LONG_VALUE; 533 if("long".equals(lcType)) return Types.LONG; 534 break; 535 case 'n': 536 if("node".equals(lcType)) return Types.NODE; 537 if("null".equals(lcType)) return Types.OBJECT; 538 if("number".equals(lcType)) return Types.DOUBLE_VALUE; 539 if("numeric".equals(lcType)) return Types.DOUBLE_VALUE; 540 break; 541 case 's': 542 if("string".equals(lcType)) return Types.STRING; 543 if("struct".equals(lcType)) return Types.STRUCT; 544 if("short".equals(type)) return Types.SHORT_VALUE; 545 if("short".equals(lcType)) return Types.SHORT; 546 break; 547 case 'o': 548 if("other".equals(lcType)) return Types.OBJECT; 549 if("object".equals(lcType)) return Types.OBJECT; 550 break; 551 case 'u': 552 if("uuid".equals(lcType)) return Types.STRING; 553 if("udf".equals(lcType)) return Types.UDF; 554 break; 555 case 'q': 556 if("query".equals(lcType)) return Types.QUERY; 557 if("querycolumn".equals(lcType)) return Types.QUERY_COLUMN; 558 break; 559 case 't': 560 if("timespan".equals(lcType)) return Types.TIMESPAN; 561 break; 562 case 'v': 563 if("variablename".equals(lcType)) return Types.STRING; 564 if("variable_name".equals(lcType)) return Types.STRING; 565 if("variablestring".equals(lcType)) return Types.STRING; 566 if("variable_string".equals(lcType)) return Types.STRING; 567 if("void".equals(lcType)) return Types.VOID; 568 break; 569 case 'x': 570 if("xml".equals(lcType)) return Types.NODE; 571 break; 572 } 573 try { 574 return Type.getType(ClassUtil.loadClass(type)); 575 } 576 catch (ClassException e) { 577 throw new BytecodeException(e.getMessage(),null); 578 } 579 580 } 581 582 @Override 583 public Expression getExpr() { 584 return expr; 585 } 586 587 /** 588 * @return the type 589 */ 590 public String getType() { 591 return type; 592 } 593 594} 595 596 597 598