/* // This software is subject to the terms of the Eclipse Public License v1.0 // Agreement, available at the following URL: // http://www.eclipse.org/legal/epl-v10.html. // Copyright (C) 2007-2010 Julian Hyde // All Rights Reserved. // You must accept the terms of that agreement to use this software. */ package org.olap4j.driver.olap4ld; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.io.StringWriter; import java.io.Writer; import java.util.AbstractList; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import org.apache.xerces.impl.Constants; import org.apache.xerces.parsers.DOMParser; import org.apache.xml.serialize.OutputFormat; import org.apache.xml.serialize.XMLSerializer; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXParseException; /** * Utility methods for the olap4j driver for XML/A. * * <p> * Many of the methods are related to XML parsing. For general-purpose methods * useful for implementing any olap4j driver, see the org.olap4j.impl package * and in particular {@link org.olap4j.impl.Olap4jUtil}. * * @author jhyde, bkaempgen * @version $Id: XmlaOlap4jUtil.java 315 2010-05-29 00:56:11Z jhyde $ * @since Dec 2, 2007 */ public abstract class Olap4ldUtil { // Debugging ? public static boolean _isDebug; // Logging? public static Logger _log; /* * XMLA prefixes */ static final String LINE_SEP = System.getProperty("line.separator", "\n"); static final String SOAP_PREFIX = "SOAP-ENV"; static final String SOAP_NS = "http://schemas.xmlsoap.org/soap/envelope/"; static final String XMLA_PREFIX = "xmla"; static final String XMLA_NS = "urn:schemas-microsoft-com:xml-analysis"; static final String MDDATASET_NS = "urn:schemas-microsoft-com:xml-analysis:mddataset"; static final String ROWSET_NS = "urn:schemas-microsoft-com:xml-analysis:rowset"; static final String XSD_PREFIX = "xsd"; static final String XMLNS = "xmlns"; static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; static final String SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; static final String FULL_SCHEMA_VALIDATION_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking"; static final String DEFER_NODE_EXPANSION = "http://apache.org/xml/features/dom/defer-node-expansion"; static final String SCHEMA_LOCATION = Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION; /** * Parse a stream into a Document (no validation). * */ static Document parse(byte[] in) throws SAXException, IOException { InputSource source = new InputSource(new ByteArrayInputStream(in)); DOMParser parser = getParser(null, null, false); try { parser.parse(source); checkForParseError(parser); } catch (SAXParseException ex) { checkForParseError(parser, ex); } return parser.getDocument(); } /** * Get your non-cached DOM parser which can be configured to do schema based * validation of the instance Document. * */ static DOMParser getParser(String schemaLocationPropertyValue, EntityResolver entityResolver, boolean validate) throws SAXNotRecognizedException, SAXNotSupportedException { boolean doingValidation = (validate || (schemaLocationPropertyValue != null)); DOMParser parser = new DOMParser(); parser.setEntityResolver(entityResolver); parser.setErrorHandler(new ErrorHandlerImpl()); parser.setFeature(DEFER_NODE_EXPANSION, false); parser.setFeature(NAMESPACES_FEATURE_ID, true); parser.setFeature(SCHEMA_VALIDATION_FEATURE_ID, doingValidation); parser.setFeature(VALIDATION_FEATURE_ID, doingValidation); if (schemaLocationPropertyValue != null) { parser.setProperty(SCHEMA_LOCATION, schemaLocationPropertyValue.replace('\\', '/')); } return parser; } /** * Checks whether the DOMParser after parsing a Document has any errors and, * if so, throws a RuntimeException exception containing the errors. */ static void checkForParseError(DOMParser parser, Throwable t) { final ErrorHandler errorHandler = parser.getErrorHandler(); if (errorHandler instanceof ErrorHandlerImpl) { final ErrorHandlerImpl saxEH = (ErrorHandlerImpl) errorHandler; final List<ErrorInfo> errors = saxEH.getErrors(); if (errors != null && errors.size() > 0) { String errorStr = ErrorHandlerImpl.formatErrorInfos(saxEH); throw new RuntimeException(errorStr, t); } } else { System.out.println("errorHandler=" + errorHandler); } } static void checkForParseError(final DOMParser parser) { checkForParseError(parser, null); } static List<Node> listOf(final NodeList nodeList) { return new AbstractList<Node>() { public Node get(int index) { return nodeList.item(index); } public int size() { return nodeList.getLength(); } }; } static String gatherText(Element element) { StringBuilder buf = new StringBuilder(); final NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { buf.append(childNodes.item(i).getTextContent()); } return buf.toString(); } static String prettyPrint(Element element) { StringBuilder string = new StringBuilder(); prettyPrintLoop(element, string, ""); return string.toString(); } private static void prettyPrintLoop(NodeList nodes, StringBuilder string, String indentation) { for (int index = 0; index < nodes.getLength(); index++) { prettyPrintLoop(nodes.item(index), string, indentation); } } private static void prettyPrintLoop(Node node, StringBuilder string, String indentation) { if (node == null) { return; } int type = node.getNodeType(); switch (type) { case Node.DOCUMENT_NODE: string.append("\n"); prettyPrintLoop(node.getChildNodes(), string, indentation + "\t"); break; case Node.ELEMENT_NODE: string.append(indentation); string.append("<"); string.append(node.getNodeName()); Attr[] attributes; if (node.getAttributes() != null) { int length = node.getAttributes().getLength(); attributes = new Attr[length]; for (int loopIndex = 0; loopIndex < length; loopIndex++) { attributes[loopIndex] = (Attr) node.getAttributes().item( loopIndex); } } else { attributes = new Attr[0]; } for (Attr attribute : attributes) { string.append(" "); string.append(attribute.getNodeName()); string.append("=\""); string.append(attribute.getNodeValue()); string.append("\""); } string.append(">\n"); prettyPrintLoop(node.getChildNodes(), string, indentation + "\t"); string.append(indentation); string.append("</"); string.append(node.getNodeName()); string.append(">\n"); break; case Node.TEXT_NODE: string.append(indentation); string.append(node.getNodeValue().trim()); string.append("\n"); break; case Node.PROCESSING_INSTRUCTION_NODE: string.append(indentation); string.append("<?"); string.append(node.getNodeName()); String text = node.getNodeValue(); if (text != null && text.length() > 0) { string.append(text); } string.append("?>\n"); break; case Node.CDATA_SECTION_NODE: string.append(indentation); string.append("<![CDATA["); string.append(node.getNodeValue()); string.append("]]>"); break; } } static Element findChild(Element element, String ns, String tag) { final NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { if (childNodes.item(i) instanceof Element) { Element child = (Element) childNodes.item(i); if (child.getLocalName().equals(tag) && (ns == null || child.getNamespaceURI().equals(ns))) { return child; } } } return null; } static String stringElement(Element row, String name) { final NodeList childNodes = row.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { final Node node = childNodes.item(i); if (name.equals(node.getLocalName())) { return node.getTextContent(); } } return null; } static Integer integerElement(Element row, String name) { final String s = stringElement(row, name); if (s == null || s.equals("")) { return null; } else { return Integer.valueOf(s); } } static int intElement(Element row, String name) { return integerElement(row, name).intValue(); } static Double doubleElement(Element row, String name) { return Double.valueOf(stringElement(row, name)); } static boolean booleanElement(Element row, String name) { return "true".equals(stringElement(row, name)); } static Float floatElement(Element row, String name) { return Float.valueOf(stringElement(row, name)); } static long longElement(Element row, String name) { return Long.valueOf(stringElement(row, name)).longValue(); } static List<Element> childElements(Element memberNode) { final List<Element> list = new ArrayList<Element>(); final NodeList childNodes = memberNode.getChildNodes(); for (int i = 0; i < childNodes.getLength(); ++i) { final Node childNode = childNodes.item(i); if (childNode instanceof Element) { list.add((Element) childNode); } } return list; } static List<Element> findChildren(Element element, String ns, String tag) { final List<Element> list = new ArrayList<Element>(); for (Node node : listOf(element.getChildNodes())) { if (tag.equals(node.getLocalName()) && ((ns == null) || node.getNamespaceURI().equals(ns))) { list.add((Element) node); } } return list; } /** * Converts a Node to a String. * * @param node * XML node * @param prettyPrint * Whether to print with nice indentation * @return String representation of XML */ public static String toString(Node node, boolean prettyPrint) { if (node == null) { return null; } try { Document doc = node.getOwnerDocument(); OutputFormat format; if (doc != null) { format = new OutputFormat(doc, null, prettyPrint); } else { format = new OutputFormat("xml", null, prettyPrint); } if (prettyPrint) { format.setLineSeparator(LINE_SEP); } else { format.setLineSeparator(""); } StringWriter writer = new StringWriter(1000); XMLSerializer serial = new XMLSerializer(writer, format); serial.asDOMSerializer(); if (node instanceof Document) { serial.serialize((Document) node); } else if (node instanceof Element) { format.setOmitXMLDeclaration(true); serial.serialize((Element) node); } else if (node instanceof DocumentFragment) { format.setOmitXMLDeclaration(true); serial.serialize((DocumentFragment) node); } else if (node instanceof Text) { Text text = (Text) node; return text.getData(); } else if (node instanceof Attr) { Attr attr = (Attr) node; String name = attr.getName(); String value = attr.getValue(); writer.write(name); writer.write("=\""); writer.write(value); writer.write("\""); if (prettyPrint) { writer.write(LINE_SEP); } } else { writer.write("node class = " + node.getClass().getName()); if (prettyPrint) { writer.write(LINE_SEP); } else { writer.write(' '); } writer.write("XmlUtil.toString: fix me: "); writer.write(node.toString()); if (prettyPrint) { writer.write(LINE_SEP); } } return writer.toString(); } catch (Exception ex) { // ignore return null; } } /** * Error handler plus helper methods. */ static class ErrorHandlerImpl implements ErrorHandler { public static final String WARNING_STRING = "WARNING"; public static final String ERROR_STRING = "ERROR"; public static final String FATAL_ERROR_STRING = "FATAL"; // DOMError values public static final short SEVERITY_WARNING = 1; public static final short SEVERITY_ERROR = 2; public static final short SEVERITY_FATAL_ERROR = 3; public void printErrorInfos(PrintStream out) { if (errors != null) { for (ErrorInfo error : errors) { out.println(formatErrorInfo(error)); } } } public static String formatErrorInfos(ErrorHandlerImpl saxEH) { if (!saxEH.hasErrors()) { return ""; } StringBuilder buf = new StringBuilder(512); for (ErrorInfo error : saxEH.getErrors()) { buf.append(formatErrorInfo(error)); buf.append(LINE_SEP); } return buf.toString(); } public static String formatErrorInfo(ErrorInfo ei) { StringBuilder buf = new StringBuilder(128); buf.append("["); switch (ei.severity) { case SEVERITY_WARNING: buf.append(WARNING_STRING); break; case SEVERITY_ERROR: buf.append(ERROR_STRING); break; case SEVERITY_FATAL_ERROR: buf.append(FATAL_ERROR_STRING); break; } buf.append(']'); String systemId = ei.exception.getSystemId(); if (systemId != null) { int index = systemId.lastIndexOf('/'); if (index != -1) { systemId = systemId.substring(index + 1); } buf.append(systemId); } buf.append(':'); buf.append(ei.exception.getLineNumber()); buf.append(':'); buf.append(ei.exception.getColumnNumber()); buf.append(": "); buf.append(ei.exception.getMessage()); return buf.toString(); } private List<ErrorInfo> errors; public ErrorHandlerImpl() { } public List<ErrorInfo> getErrors() { return this.errors; } public boolean hasErrors() { return (this.errors != null); } public void warning(SAXParseException exception) throws SAXException { addError(new ErrorInfo(SEVERITY_WARNING, exception)); } public void error(SAXParseException exception) throws SAXException { addError(new ErrorInfo(SEVERITY_ERROR, exception)); } public void fatalError(SAXParseException exception) throws SAXException { addError(new ErrorInfo(SEVERITY_FATAL_ERROR, exception)); } protected void addError(ErrorInfo ei) { if (this.errors == null) { this.errors = new ArrayList<ErrorInfo>(); } this.errors.add(ei); } public String getFirstError() { return (hasErrors()) ? formatErrorInfo(errors.get(0)) : ""; } } static class ErrorInfo { final SAXParseException exception; final short severity; ErrorInfo(short severity, SAXParseException exception) { this.severity = severity; this.exception = exception; } } /** * * Reused from * http://viralpatel.net/blogs/getting-jvm-heap-size-used-memory- * total-memory-using-java-runtime/ Class: TestMemory * * @author: Viral Patel * @description: Prints JVM memory utilization statistics * @returns memory in mb */ public static long getFreeMemory() { // kilo -> mega byte int mb = 1024 * 1024; // Getting the runtime reference from system Runtime runtime = Runtime.getRuntime(); Olap4ldUtil._log.config("##### Heap utilization statistics [MB] #####"); // Print used memory Olap4ldUtil._log.config("Used Memory:" + (runtime.totalMemory() - runtime.freeMemory()) / mb); // Print free memory Olap4ldUtil._log.config("Free Memory:" + runtime.freeMemory() / mb); // Print total available memory Olap4ldUtil._log.config("Total Memory:" + runtime.totalMemory() / mb); // Print Maximum available memory Olap4ldUtil._log.config("Max Memory:" + runtime.maxMemory() / mb); return runtime.freeMemory(); } // this method is invoked in the main method // to initialize the logging. public static void prepareLogging() { File loggingConfigurationFile = new File("logging.properties"); System.out.println("Logging properties file absolute path:" + loggingConfigurationFile.getAbsolutePath()); // Setup logging Olap4ldUtil._log = Logger.getLogger("Olap4ldDriver"); Olap4ldUtil._log.setLevel(Level.ALL); // it only generates the configuration file // if it really doesn't exist. if (!loggingConfigurationFile.exists()) { Writer output = null; try { output = new BufferedWriter(new FileWriter( loggingConfigurationFile)); // The configuration file is a property file. // The Properties class gives support to // define and persist the logging configuration. Properties logConf = new Properties(); logConf.setProperty("handlers", "java.util.logging.FileHandler," + "java.util.logging.ConsoleHandler"); logConf.setProperty(".level", "INFO"); logConf.setProperty("java.util.logging.ConsoleHandler.level", "INFO"); logConf.setProperty( "java.util.logging.ConsoleHandler.formatter", "java.util.logging.SimpleFormatter"); // level logConf.setProperty("java.util.logging.FileHandler.level", "INFO"); // pattern // Will be for example at /home/benedikt/Programs/eclipse_juno_jdk_20120721/ logConf.setProperty("java.util.logging.FileHandler.pattern", "log/olap4ld_%u.log"); // limit in bytes logConf.setProperty("java.util.logging.FileHandler.limit", "10000000"); // roll // logConf.setProperty("java.util.logging.FileHandler.count", // "0"); // append logConf.setProperty("java.util.logging.FileHandler.append", "1"); // Maybe better XMLFormatter? logConf.setProperty("java.util.logging.FileHandler.formatter", "java.util.logging.SimpleFormatter"); logConf.store(output, "Generated"); } catch (IOException ex) { Olap4ldUtil._log.log(Level.WARNING, "Logging configuration file not created", ex); } finally { try { output.close(); } catch (IOException ex) { Olap4ldUtil._log.log(Level.WARNING, "Problems to save " + "the logging configuration file in the disc", ex); } } } // This is the way to define the system // property without changing the command line. // It has the same effect of the parameter // -Djava.util.logging.config.file Properties prop = System.getProperties(); prop.setProperty("java.util.logging.config.file", "logging.properties"); // It creates the log directory if it doesn't exist // In the configuration file above we specify this // folder to store log files: // logConf.setProperty( // "java.util.logging.FileHandler.pattern", // "log/application.log"); File logDir = new File("log"); if (!logDir.exists()) { Olap4ldUtil._log.info("Creating the logging directory"); logDir.mkdir(); } // It overwrites the current logging configuration // to the one in the configuration file. try { LogManager.getLogManager().readConfiguration(); } catch (IOException ex) { Olap4ldUtil._log.log(Level.WARNING, "Problems to load the logging " + "configuration file", ex); } // More specific loggers // They do not work, properly. Seem to either not log at all or create // many lck and log files // Handler handler; // try { // Date date = new Date(); // String formattedDate = new // SimpleDateFormat("yyyy-MM-dd_hh_mm_ss").format(date); // String pattern = "log/olap4ld_connection_"+ formattedDate + ".log"; // handler = new FileHandler(pattern); // handler.setFormatter(new java.util.logging.SimpleFormatter()); // handler.setLevel(Level.INFO); // Olap4ldUtil._log.addHandler(handler); // // // one file for logging // handler = new FileHandler("log/olap4ld_all.log"); // handler.setLevel(Level.INFO); // handler.setFormatter(new java.util.logging.SimpleFormatter()); // Olap4ldUtil._log.addHandler(handler); // } catch (SecurityException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } catch (IOException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } Olap4ldUtil._log.setLevel(Level.ALL); Olap4ldUtil._log.config("Logging properties file absolute path:" + loggingConfigurationFile.getAbsolutePath()); // // We want to log to a file. // try { // Handler handler = new FileHandler("log/olap4ld.log", LOG_SIZE, // LOG_ROTATION_COUNT); // Olap4ldUtil._log.addHandler(handler); // } catch (SecurityException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // Set the level to that of its parent // LdOlap4jUtil._log.setLevel(null); // Turn off all logging // LdOlap4jUtil._log.setLevel(Level.OFF); // System.out.println("Test"); <= We get to this point // Turn on all logging // LdOlap4jUtil._log.setLevel(Level.ALL); } } // End XmlaOlap4jUtil.java