1 28 package net.sf.jasperreports.olap; 29 30 import java.io.StringReader ; 31 import java.util.Arrays ; 32 import java.util.HashMap ; 33 import java.util.Iterator ; 34 import java.util.List ; 35 import java.util.Map ; 36 37 import net.sf.jasperreports.engine.JRDataSource; 38 import net.sf.jasperreports.engine.JRDataset; 39 import net.sf.jasperreports.engine.JRException; 40 import net.sf.jasperreports.engine.JRField; 41 import net.sf.jasperreports.engine.JRRuntimeException; 42 import net.sf.jasperreports.olap.mapping.AxisPosition; 43 import net.sf.jasperreports.olap.mapping.DataMapping; 44 import net.sf.jasperreports.olap.mapping.Mapping; 45 import net.sf.jasperreports.olap.mapping.MappingLexer; 46 import net.sf.jasperreports.olap.mapping.MappingMetadata; 47 import net.sf.jasperreports.olap.mapping.MappingParser; 48 import net.sf.jasperreports.olap.mapping.MemberDepth; 49 import net.sf.jasperreports.olap.mapping.MemberMapping; 50 import net.sf.jasperreports.olap.mapping.MemberProperty; 51 import net.sf.jasperreports.olap.mapping.Tuple; 52 import net.sf.jasperreports.olap.mapping.TuplePosition; 53 import net.sf.jasperreports.olap.result.JROlapCell; 54 import net.sf.jasperreports.olap.result.JROlapHierarchy; 55 import net.sf.jasperreports.olap.result.JROlapHierarchyLevel; 56 import net.sf.jasperreports.olap.result.JROlapMember; 57 import net.sf.jasperreports.olap.result.JROlapMemberTuple; 58 import net.sf.jasperreports.olap.result.JROlapResult; 59 import net.sf.jasperreports.olap.result.JROlapResultAxis; 60 61 import org.apache.commons.logging.Log; 62 import org.apache.commons.logging.LogFactory; 63 64 import antlr.ANTLRException; 65 66 67 71 public class JROlapDataSource implements JRDataSource, MappingMetadata 72 { 73 private static final Log log = LogFactory.getLog(JROlapDataSource.class); 74 75 protected final JROlapResult olapResult; 76 protected JROlapResultAxis[] axes; 77 protected final JROlapHierarchy[][] queryHierarchies; 78 protected final int hierarchiesCount; 79 80 protected Map fieldMatchers; 81 protected int[][] fieldsMaxDepths; 82 protected boolean[] iteratePositions; 83 protected boolean iterate; 84 85 protected boolean dataField; 86 87 protected Map fieldValues; 88 protected int[] axisPositions; 89 protected boolean first; 90 protected int[][] maxDepths; 91 92 public JROlapDataSource(JRDataset dataset, JROlapResult result) 93 { 94 this.olapResult = result; 95 axes = result.getAxes(); 96 97 queryHierarchies = new JROlapHierarchy[axes.length][]; 98 fieldsMaxDepths = new int[axes.length][]; 99 maxDepths = new int[axes.length][]; 100 int hCount = 0; 101 for (int i = 0; i < axes.length; i++) 102 { 103 queryHierarchies[i] = axes[i].getHierarchiesOnAxis(); 104 105 hCount += queryHierarchies[i].length; 106 fieldsMaxDepths[i] = new int[queryHierarchies[i].length]; 107 maxDepths[i] = new int[queryHierarchies[i].length]; 108 } 109 hierarchiesCount = hCount; 110 111 axisPositions = new int[axes.length]; 112 113 init(dataset); 114 } 115 116 public boolean next() throws JRException 117 { 118 boolean next; 119 boolean matchMaxLevel; 120 do 121 { 122 if (iterate) 123 { 124 next = nextPositions(); 125 } 126 else 127 { 128 next = first; 129 first = false; 130 } 131 132 if (!next) 133 { 134 break; 135 } 136 137 resetMaxDepths(); 138 for (Iterator it = fieldMatchers.entrySet().iterator(); it.hasNext();) 139 { 140 Map.Entry entry = (Map.Entry ) it.next(); 141 Object fieldName = entry.getKey(); 142 FieldMatcher matcher = (FieldMatcher) entry.getValue(); 143 if (matcher.matches()) 144 { 145 Object value = matcher.value(); 146 fieldValues.put(fieldName, value); 147 } 148 } 149 150 matchMaxLevel = true; 151 axes_loop: 152 for (int i = 0; i < axes.length; i++) 153 { 154 if (iteratePositions[i]) 155 { 156 for (int j = 0; j < fieldsMaxDepths[i].length; j++) 157 { 158 if (maxDepths[i][j] < fieldsMaxDepths[i][j]) 159 { 160 matchMaxLevel = false; 161 break axes_loop; 162 } 163 } 164 } 165 } 166 } 167 while (!matchMaxLevel); 168 169 return next; 170 } 171 172 173 private void resetMaxDepths() 174 { 175 for (int i = 0; i < axes.length; ++i) 176 { 177 if (iteratePositions[i]) 178 { 179 for (int j = 0; j < maxDepths[i].length; j++) 180 { 181 maxDepths[i][j] = 0; 182 } 183 } 184 } 185 } 186 187 protected boolean nextPositions() 188 { 189 boolean next; 190 int i = 0; 191 for (; i < axes.length; ++i) 192 { 193 if (iteratePositions[i]) 194 { 195 ++axisPositions[i]; 196 if (axisPositions[i] >= axes[i].getTupleCount()) 197 { 198 axisPositions[i] = 0; 199 } 200 else 201 { 202 break; 203 } 204 } 205 } 206 207 next = i < axes.length; 208 return next; 209 } 210 211 public Object getFieldValue(JRField jrField) throws JRException 212 { 213 return fieldValues.get(jrField.getName()); 214 } 215 216 217 private void init(JRDataset dataset) 218 { 219 iteratePositions = new boolean[axes.length]; 220 221 fieldMatchers = new HashMap (); 222 223 dataField = false; 224 JRField[] fields = dataset.getFields(); 225 if (fields != null) 226 { 227 for (int i = 0; i < fields.length; i++) 228 { 229 JRField field = fields[i]; 230 String fieldMapping = getFieldMapping(field); 231 232 MappingLexer lexer = new MappingLexer(new StringReader (fieldMapping)); 233 MappingParser parser = new MappingParser(lexer); 234 parser.setMappingMetadata(this); 235 Mapping mapping; 236 try 237 { 238 mapping = parser.mapping(); 239 } 240 catch (ANTLRException e) 241 { 242 log.error("Error parsing field mapping", e); 243 throw new JRRuntimeException(e); 244 } 245 246 if (mapping == null) 247 { 248 throw new JRRuntimeException("Invalid field mapping \"" + fieldMapping + "\"."); 249 } 250 251 processMappingMembers(mapping); 252 253 FieldMatcher fieldMatcher = createFieldMatcher(mapping); 254 fieldMatchers.put(field.getName(), fieldMatcher); 255 } 256 } 257 258 if (!dataField) 259 { 260 Arrays.fill(iteratePositions, true); 261 } 262 263 initIterate(); 264 } 265 266 private void processMappingMembers(Mapping mapping) 267 { 268 for (Iterator it = mapping.memberMappings(); it.hasNext();) 269 { 270 net.sf.jasperreports.olap.mapping.Member member = (net.sf.jasperreports.olap.mapping.Member) it.next(); 271 processMemberInfo(member); 272 } 273 } 274 275 private FieldMatcher createFieldMatcher(Mapping mapping) 276 { 277 FieldMatcher fieldMatcher; 278 if (mapping instanceof MemberMapping) 279 { 280 fieldMatcher = new MemberFieldMatcher((MemberMapping) mapping); 281 } 282 else if (mapping instanceof DataMapping) 283 { 284 dataField = true; 285 fieldMatcher = new DataFieldMatcher((DataMapping) mapping); 286 } 287 else 288 { 289 throw new JRRuntimeException("internal error"); 290 } 291 292 return fieldMatcher; 293 } 294 295 protected String getFieldMapping(JRField field) 296 { 297 return field.getDescription(); 298 } 299 300 private void initIterate() 301 { 302 int firstPos = 0; 303 while (firstPos < axes.length && !iteratePositions[firstPos]) 304 { 305 ++firstPos; 306 } 307 308 if (firstPos < axes.length) 309 { 310 iterate = true; 311 axisPositions[firstPos] = -1; 312 } 313 else 314 { 315 iterate = false; 316 first = true; 317 } 318 319 fieldValues = new HashMap (); 320 } 321 322 323 protected void processMemberInfo(net.sf.jasperreports.olap.mapping.Member member) 324 { 325 MemberDepth memberDepth = member.getDepth(); 326 if (memberDepth != null) 327 { 328 int depth = memberDepth.getDepth(); 329 int axis = member.getAxis().getIdx(); 330 int idx = member.getPosition().getIdx(); 331 332 if (depth > fieldsMaxDepths[axis][idx]) 333 { 334 fieldsMaxDepths[axis][idx] = depth; 335 } 336 } 337 } 338 339 340 public int getDimensionIndex(net.sf.jasperreports.olap.mapping.Axis axis, String dimension) 341 { 342 JROlapHierarchy[] hierarchies = axes[axis.getIdx()].getHierarchiesOnAxis(); 343 int dimensionIndex = -1; 344 for (int i = 0; i < hierarchies.length; i++) 345 { 346 JROlapHierarchy hierarchy = hierarchies[i]; 347 if (hierarchy.getDimensionName().equals(dimension)) 348 { 349 dimensionIndex = i; 350 } 351 } 352 353 if (dimensionIndex == -1) 354 { 355 throw new JRRuntimeException("Could not find dimension \"" + dimension + "\" on axis " + axis.getIdx() + "."); 356 } 357 358 return dimensionIndex; 359 } 360 361 public int getLevelDepth(TuplePosition pos, String levelName) 362 { 363 JROlapHierarchy hierarchy = axes[pos.getAxis().getIdx()].getHierarchiesOnAxis()[pos.getIdx()]; 364 JROlapHierarchyLevel[] levels = hierarchy.getLevels(); 365 int levelIndex = -1; 366 for (int i = 0; i < levels.length; i++) 367 { 368 JROlapHierarchyLevel level = levels[i]; 369 if (level != null && level.getName().equals(levelName)) 370 { 371 levelIndex = level.getDepth(); 372 break; 373 } 374 } 375 376 if (levelIndex == -1) 377 { 378 throw new JRRuntimeException("Could not find level \"" + levelName + "\" on hierarchy " + hierarchy.getDimensionName() + "."); 379 } 380 381 return levelIndex; 382 } 383 384 385 protected void setMatchMemberDepth(net.sf.jasperreports.olap.mapping.Member memberInfo, JROlapMember member) 386 { 387 int memberDepth = member.getDepth(); 388 int axis = memberInfo.getAxis().getIdx(); 389 int pos = memberInfo.getPosition().getIdx(); 390 if (maxDepths[axis][pos] < memberDepth) 391 { 392 maxDepths[axis][pos] = memberDepth; 393 } 394 } 395 396 397 protected abstract class FieldMatcher 398 { 399 public abstract boolean matches(); 400 401 public abstract Object value(); 402 403 public final JROlapMember member(net.sf.jasperreports.olap.mapping.Member memberInfo, int[] positions) 404 { 405 int axisIdx = memberInfo.getAxis().getIdx(); 406 JROlapResultAxis axis = axes[axisIdx]; 407 JROlapMemberTuple tuple = axis.getTuple(positions[axisIdx]); 408 JROlapMember[] members = tuple.getMembers(); 409 int pos = memberInfo.getPosition().getIdx(); 410 return members[pos]; 411 } 412 } 413 414 protected class MemberFieldMatcher extends FieldMatcher 415 { 416 final net.sf.jasperreports.olap.mapping.Member memberInfo; 417 final MemberProperty property; 418 JROlapMember member; 419 420 MemberFieldMatcher(MemberMapping mapping) 421 { 422 this.memberInfo = mapping.getMember(); 423 this.property = mapping.getProperty(); 424 } 425 426 public boolean matches() 427 { 428 member = member(memberInfo, axisPositions); 429 setMatchMemberDepth(memberInfo, member); 430 member = memberInfo.ancestorMatch(member); 431 return member != null; 432 } 433 434 public Object value() 435 { 436 Object value; 437 if (property != null) 438 { 439 value = member.getPropertyValue(property.getName()); 440 } 441 else if (memberInfo.getDepth() == null) 442 { 443 value = member.getMondrianMember(); 444 } 445 else 446 { 447 value = member.getName(); 448 } 449 return value; 450 } 451 } 452 453 454 protected class DataFieldMatcher extends FieldMatcher 455 { 456 private final boolean formatted; 457 private final int[] dataPositions; 458 private final net.sf.jasperreports.olap.mapping.Member[] members; 459 private int[] positions; 460 461 public DataFieldMatcher(DataMapping mapping) 462 { 463 this.formatted = mapping.isFormatted(); 464 465 List mappingPositions = mapping.getPositions(); 466 if (mappingPositions == null) 467 { 468 this.dataPositions = null; 469 positions = axisPositions; 470 } 471 else 472 { 473 if (mappingPositions.size() != axes.length) 474 { 475 throw new JRRuntimeException("Incorrect data mapping: the number of positions doesn't match the number of axes."); 476 } 477 478 this.dataPositions = new int[axes.length]; 479 int c = 0; 480 for (Iterator iter = mappingPositions.iterator(); iter.hasNext(); ++c) 481 { 482 AxisPosition position = (AxisPosition) iter.next(); 483 int pos; 484 if (position.isSpecified()) 485 { 486 pos = position.getPosition(); 487 } 488 else 489 { 490 pos = -1; 491 iteratePositions[c] = true; 492 } 493 dataPositions[c] = pos; 494 } 495 } 496 497 List filter = mapping.getFilter(); 498 if (filter == null || filter.isEmpty()) 499 { 500 this.members = null; 501 } 502 else 503 { 504 this.members = new net.sf.jasperreports.olap.mapping.Member[filter.size()]; 505 filter.toArray(this.members); 506 } 507 } 508 509 public boolean matches() 510 { 511 if (dataPositions != null) 512 { 513 setPositions(); 514 } 515 516 boolean matches = true; 517 if (members != null) 518 { 519 for (int i = 0; i < members.length; i++) 520 { 521 net.sf.jasperreports.olap.mapping.Member memberInfo = members[i]; 522 JROlapMember member = member(memberInfo, positions); 523 setMatchMemberDepth(memberInfo, member); 524 if (!memberInfo.matches(member)) 525 { 526 matches = false; 527 break; 528 } 529 } 530 } 531 532 return matches; 533 } 534 535 public Object value() 536 { 537 JROlapCell cell = olapResult.getCell(positions); 538 539 if (cell != null && cell.isError()) 540 { 541 throw new JRRuntimeException("OLAP cell calculation returned error."); 542 } 543 544 Object value; 545 if (cell == null || cell.isNull()) 546 { 547 value = null; 548 } 549 else if (formatted) 550 { 551 value = cell.getFormattedValue(); 552 } 553 else 554 { 555 value = cell.getValue(); 556 } 557 558 return value; 559 } 560 561 void setPositions() 562 { 563 positions = new int[axes.length]; 564 for (int i = 0; i < axes.length; i++) 565 { 566 int dataPosition = dataPositions[i]; 567 positions[i] = dataPosition == -1 ? axisPositions[i] : dataPosition; 568 } 569 } 570 } 571 572 573 public int getTuplePosition(int axisIndex, Tuple tuple) 574 { 575 if (axisIndex > axes.length) 576 { 577 throw new JRRuntimeException("OLAP result doesn't contain Axis(" + axisIndex + ")."); 578 } 579 580 String [] memberUniqueNames = tuple.getMemberUniqueNames(); 581 JROlapResultAxis axis = axes[axisIndex]; 582 int tupleCount = axis.getTupleCount(); 583 584 int pos = -1; 585 for (int i = 0; i < tupleCount; i++) 586 { 587 JROlapMemberTuple memberTuple = axis.getTuple(i); 588 JROlapMember[] resMembers = memberTuple.getMembers(); 589 if (resMembers.length == memberUniqueNames.length) 590 { 591 boolean eq = true; 592 for (int j = 0; eq && j < resMembers.length; ++j) 593 { 594 if (!memberUniqueNames[j].equals(resMembers[j].getUniqueName())) 595 { 596 eq = false; 597 } 598 } 599 600 if (eq) 601 { 602 pos = i; 603 break; 604 } 605 } 606 } 607 608 if (pos == -1) 609 { 610 StringBuffer sb = new StringBuffer (); 611 sb.append('('); 612 for (int i = 0; i < memberUniqueNames.length; i++) 613 { 614 if (i > 0) 615 { 616 sb.append(','); 617 } 618 sb.append(memberUniqueNames[i]); 619 } 620 throw new JRRuntimeException("No such tuple " + sb + " on axis " + axisIndex + "."); 621 } 622 623 return pos; 624 } 625 } 626 | Popular Tags |