1 12 package mondrian.xmla; 13 14 import java.util.*; 15 16 import mondrian.olap.Util; 17 18 import org.apache.log4j.Logger; 19 20 29 abstract class Rowset implements XmlaConstants { 30 protected static final Logger LOGGER = Logger.getLogger(Rowset.class); 31 32 protected final RowsetDefinition rowsetDefinition; 33 protected final Map<String , List<String >> restrictions; 34 protected final Map<String , String > properties; 35 protected final XmlaRequest request; 36 protected final XmlaHandler handler; 37 private final RowsetDefinition.Column[] restrictedColumns; 38 39 46 Rowset(RowsetDefinition definition, XmlaRequest request, XmlaHandler handler) { 47 this.rowsetDefinition = definition; 48 this.restrictions = request.getRestrictions(); 49 this.properties = request.getProperties(); 50 this.request = request; 51 this.handler = handler; 52 ArrayList<RowsetDefinition.Column> list = 53 new ArrayList<RowsetDefinition.Column>(); 54 for (Map.Entry<String , List<String >> restrictionEntry : 55 restrictions.entrySet()) 56 { 57 String restrictedColumn = restrictionEntry.getKey(); 58 LOGGER.debug( 59 "Rowset<init>: restrictedColumn=\"" + restrictedColumn + "\""); 60 final RowsetDefinition.Column column = definition.lookupColumn( 61 restrictedColumn); 62 if (column == null) { 63 throw Util.newError("Rowset '" + definition.name() + 64 "' does not contain column '" + restrictedColumn + "'"); 65 } 66 if (!column.restriction) { 67 throw Util.newError("Rowset '" + definition.name() + 68 "' column '" + restrictedColumn + 69 "' does not allow restrictions"); 70 } 71 final List<String > requiredValue = restrictionEntry.getValue(); 73 if (requiredValue.size() > 1) { 74 final RowsetDefinition.Type type = column.type; 75 switch (type) { 76 case StringArray: 77 case EnumerationArray: 78 case StringSometimesArray: 79 break; default: 81 throw Util.newError("Rowset '" + definition.name() + 82 "' column '" + restrictedColumn + 83 "' can only be restricted on one value at a time"); 84 } 85 } 86 list.add(column); 87 } 88 list = pruneRestrictions(list); 89 this.restrictedColumns = 90 list.toArray( 91 new RowsetDefinition.Column[list.size()]); 92 for (Map.Entry<String , String > propertyEntry : properties.entrySet()) { 93 String propertyName = propertyEntry.getKey(); 94 final PropertyDefinition propertyDef = 95 Util.lookup(PropertyDefinition.class, propertyName); 96 if (propertyDef == null) { 97 throw Util.newError("Rowset '" + definition.name() + 98 "' does not support property '" + propertyName + "'"); 99 } 100 final String propertyValue = propertyEntry.getValue(); 101 setProperty(propertyDef, propertyValue); 102 } 103 } 104 105 protected ArrayList<RowsetDefinition.Column> pruneRestrictions( 106 ArrayList<RowsetDefinition.Column> list) 107 { 108 return list; 109 } 110 111 119 protected void setProperty(PropertyDefinition propertyDef, String value) { 120 switch (propertyDef) { 121 case Format: 122 break; 123 case DataSourceInfo: 124 break; 125 case Catalog: 126 break; 127 case LocaleIdentifier: 128 if ((value != null) && (value.equals("1033"))) { 132 return; 133 } 134 default: 136 LOGGER.warn("Warning: Rowset '" + rowsetDefinition.name() + 137 "' does not support property '" + propertyDef.name() + 138 "' (value is '" + value + "')"); 139 } 140 } 141 142 145 public final void unparse(XmlaResponse response) throws XmlaException 146 { 147 List<Row> rows = new ArrayList<Row>(); 148 populate(response, rows); 149 Comparator<Row> comparator = rowsetDefinition.getComparator(); 150 if (comparator != null) { 151 Collections.sort(rows, comparator); 152 } 153 for (Row row : rows) { 154 emit(row, response); 155 } 156 } 157 158 161 public abstract void populate(XmlaResponse response, List<Row> rows) throws XmlaException; 162 163 170 protected final boolean addRow(Row row, List<Row> rows) throws XmlaException { 171 return rows.add(row); 172 } 173 174 181 protected void emit(Row row, XmlaResponse response) throws XmlaException { 182 183 SaxWriter writer = response.getWriter(); 184 185 writer.startElement("row"); 186 for (RowsetDefinition.Column column : rowsetDefinition.columnDefinitions) { 187 Object value = row.get(column.name); 188 if (value == null) { 189 if (!column.nullable) { 190 throw new XmlaException( 191 CLIENT_FAULT_FC, 192 HSB_BAD_NON_NULLABLE_COLUMN_CODE, 193 HSB_BAD_NON_NULLABLE_COLUMN_FAULT_FS, 194 Util.newInternal("Value required for column " + 195 column.name + 196 " of rowset " + 197 rowsetDefinition.name())); 198 } 199 } else if (value instanceof XmlElement[]) { 200 XmlElement[] elements = (XmlElement[]) value; 201 for (XmlElement element : elements) { 202 emitXmlElement(writer, element); 203 } 204 } else if (value instanceof Object []) { 205 Object [] values = (Object []) value; 206 for (Object value1 : values) { 207 writer.startElement(column.name); 208 writer.characters(value1.toString()); 209 writer.endElement(); 210 } 211 } else if (value instanceof List) { 212 List values = (List) value; 213 for (Object value1 : values) { 214 if (value1 instanceof XmlElement) { 215 XmlElement xmlElement = (XmlElement) value1; 216 emitXmlElement(writer, xmlElement); 217 } else { 218 writer.startElement(column.name); 219 writer.characters(value1.toString()); 220 writer.endElement(); 221 } 222 } 223 } else { 224 writer.startElement(column.name); 225 writer.characters(value.toString()); 226 writer.endElement(); 227 } 228 } 229 writer.endElement(); 230 } 231 232 private void emitXmlElement(SaxWriter writer, XmlElement element) { 233 if (element.attributes == null) { 234 writer.startElement(element.tag); 235 } else { 236 writer.startElement(element.tag, element.attributes); 237 } 238 239 if (element.text == null) { 240 for (XmlElement aChildren : element.children) { 241 emitXmlElement(writer, aChildren); 242 } 243 } else { 244 writer.characters(element.text); 245 } 246 247 writer.endElement(); 248 } 249 250 255 protected void emit(Object row, XmlaResponse response) 256 throws XmlaException { 257 SaxWriter writer = response.getWriter(); 258 259 writer.startElement("row"); 260 for (RowsetDefinition.Column column : rowsetDefinition.columnDefinitions) { 261 Object value = column.get(row); 262 if (value != null) { 263 writer.startElement(column.name); 264 writer.characters(value.toString()); 265 writer.endElement(); 266 } else { 267 writer.startElement(column.name); 268 writer.endElement(); 269 } 270 } 271 writer.endElement(); 272 } 273 274 277 protected <E extends Enum <E>> void emit( 278 Class <E> clazz, 279 XmlaResponse response) 280 throws XmlaException 281 { 282 final E[] valuesSortedByName = clazz.getEnumConstants().clone(); 283 Arrays.sort( 284 valuesSortedByName, 285 new Comparator<E>() { 286 public int compare(E o1, E o2) { 287 return o1.name().compareTo(o2.name()); 288 } 289 }); 290 for (E value : valuesSortedByName) { 291 emit(value, response); 292 } 293 } 294 295 311 312 322 static abstract class RestrictionTest { 323 public abstract boolean passes(Object value); 324 } 325 326 RestrictionTest getRestrictionTest(RowsetDefinition.Column column) { 327 final List<String > requiredValue = restrictions.get(column.name); 328 332 333 if (requiredValue == null) { 334 return new RestrictionTest() { 335 public boolean passes(int ival) { 336 return true; 337 } 338 public boolean passes(Object value) { 339 return true; 340 } 341 }; 342 } else { 343 return new RestrictionTest() { 344 public boolean passes(Object value) { 345 return requiredValue.contains(value); 346 } 347 }; 348 } 349 } 350 351 355 private List<String > getRestrictionValue(RowsetDefinition.Column column) { 356 return restrictions.get(column.name); 357 } 358 359 366 String getRestrictionValueAsString(RowsetDefinition.Column column) { 367 List<String > rval = getRestrictionValue(column); 368 return rval != null && rval.size() == 1 ? rval.get(0) : null; 369 } 370 371 376 int getRestrictionValueAsInt(RowsetDefinition.Column column) { 377 List<String > rval = getRestrictionValue(column); 378 if (rval != null && rval.size() == 1) { 379 try { 380 return Integer.parseInt(rval.get(0)); 381 } catch (NumberFormatException ex) { 382 LOGGER.info("Rowset.getRestrictionValue: "+ 383 "bad integer restriction \""+ 384 rval+ 385 "\""); 386 return -1; 387 } 388 } else { 389 return -1; 390 } 391 } 392 393 394 395 400 protected boolean isRestricted(RowsetDefinition.Column column) { 401 return (restrictions.get(column.name) != null); 402 } 403 404 410 protected class Row { 411 private final ArrayList<String > names; 412 private final ArrayList<Object > values; 413 Row() { 414 this.names = new ArrayList<String >(); 415 this.values = new ArrayList<Object >(); 416 } 417 418 void set(String name, Object value) { 419 this.names.add(name); 420 this.values.add(value); 421 } 422 423 void set(String name, boolean value) { 424 set(name, value ? "true" : "false"); 425 } 426 427 431 public Object get(String name) { 432 int i = this.names.indexOf(name); 433 return (i < 0) ? null : this.values.get(i); 434 } 435 } 436 437 440 protected class XmlElement { 441 private final String tag; 442 private final String [] attributes; 443 private final String text; 444 private final XmlElement[] children; 445 446 XmlElement(String tag, String [] attributes) { 447 this(tag, attributes, null, null); 448 } 449 450 XmlElement(String tag, String [] attributes, String text) { 451 this(tag, attributes, text, null); 452 } 453 454 XmlElement(String tag, String [] attributes, XmlElement[] children) { 455 this(tag, attributes, null, children); 456 } 457 458 private XmlElement(String tag, String [] attributes, String text, XmlElement[] children) { 459 this.tag = tag; 460 this.attributes = attributes; 461 this.text = text; 462 this.children = children; 463 } 464 } 465 } 466 467 | Popular Tags |