/*
 * Olap_1.java
 *
 * Copyright 2004-2006 by SAP AG. All Rights Reserved.
 * SAP, R/3, mySAP, mySAP.com, xApps, xApp, SAP NetWeaver, and other SAP 
 * products and services mentioned herein as well as their respective logos 
 * are trademarks or registered trademarks of SAP AG in Germany and in several 
 * other countries all over the world. All other product and service names 
 * mentioned are the trademarks of their respective companies. Data contained 
 * in this document serves informational purposes only. National product 
 * specifications may vary.
 *
 * These materials are subject to change without notice. These materials are 
 * provided by SAP AG and its affiliated companies ("SAP Group") for 
 * informational purposes only, without representation or warranty of any kind, 
 * and SAP Group shall not be liable for errors or omissions with respect to 
 * the materials. The only warranties for SAP Group products and services are 
 * those that are set forth in the express warranty statements accompanying 
 * such products and services, if any. Nothing herein should be construed as 
 * constituting an additional warranty.
 */
package com.sap.ip.bi.sdk.samples;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Locale;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.omg.cwm.analysis.olap.Cube;
import org.omg.cwm.analysis.olap.CubeDimensionAssociation;
import org.omg.cwm.analysis.olap.Dimension;
import org.omg.cwm.analysis.olap.HierarchyLevelAssociation;
import org.omg.cwm.analysis.olap.Level;
import org.omg.cwm.analysis.olap.LevelBasedHierarchy;
import org.omg.cwm.analysis.olap.Measure;
import org.omg.cwm.analysis.olap.Schema;
import org.omg.cwm.objectmodel.core.Attribute;
import org.omg.cwm.objectmodel.core.ModelElement;
import org.omg.cwm.objectmodel.core.TaggedValue;

import com.sap.exception.IBaseException;
import com.sap.ip.bi.sdk.dac.connector.IBIConnection;
import com.sap.ip.bi.sdk.dac.connector.IBIOlap;
import com.sap.ip.bi.sdk.dac.connector.IBIOlapObjectFinder;
import com.sap.ip.bi.sdk.dac.result.IBIResultSet;
import com.sap.ip.bi.sdk.exception.BIException;
import com.sap.ip.bi.sdk.exception.BIResourceException;
import com.sap.ip.bi.sdk.localization.sdk.samples.Samples;
import com.sap.ip.bi.sdk.samples.servlet.MinimalServletContainer;

/**
 * Accessing metadata -
 *
 * This sample demonstrates four different ways to retrieve OLAP
 * metadata:
 *
 * 1.  via connection-level methods
 * 2.  via ObjectFinder methods
 * 3.  via JMI methods
 * 4.  via member data access methods
 *
 * View the HTML rendered by this servlet in the following file:
 * [SDK archive]/docs/examples/olap_1.result.html
 *
 * @author  SAP
 * @version 3.50
 * @since   3.50
 */
public class Olap_1 extends HttpServlet {
  private final static String CONTENT_TYPE = "text/html";
  private IBIOlap olap = null;

  public void init(ServletConfig config) throws ServletException {
    super.init(config);
  }

  public void doGet(
    HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {

    response.setContentType(CONTENT_TYPE);
    PrintWriter out = response.getWriter();

    out.println(Helpers.getDocTypeDefinition());
    out.println("<html>");
    out.println("<head><title>Olap_1</title>");
    out.println(Helpers.getStyleSheetDefinition());
    out.println("</head><body>");

    try {

      // ********************************************************
      // Connect to a data source.
      // ********************************************************
      IBIConnection connection = Helpers.connectToXMLADatasource(out);
      olap = connection.getOlap();

      //*********************************************************
      // Retrieve metadata via
      // connection-level methods: getSchema(), getCube(),
      // getMemberData(), getTaggedValue().
      // These methods allow you to browse top-level metadata
      // objects such as cubes and schema.
      // Typically, the objects retrieved are used then as an
      // entry point to further "navigate" to objects that are
      // contained in these name-space-like objects.
      //*********************************************************
      out.println("<br/><hr/>");
      out.println("<h3>Accessing metadata via connection-level methods</h3>");

      {
        // the list of schemas contained in the connected resource
        out.println("<h4>Schemas retrieved with olap.getSchema()</h4>");
        out.println("<table><tr><td class=\"single\">");
        int k = 0;
        for (Iterator i = olap.getSchema().iterator(); i.hasNext(); k++) {
          Schema schema = (Schema) i.next();
          if (k > 0) {
            out.println(", ");
          }
          out.println(
            (schema.getName() == null || schema.getName().equals("")) ?
            "&lt;null&gt;" : schema.getName());
        }
        out.println("</td></tr></table>");
      }

      {
        // the list of cubes contained in the connected resource
        out.println("<h4>Cubes retrieved with olap.getCube()</h4>");
        out.println("<table><tr><td class=\"single\">");
        int k = 0;
        for (Iterator i = olap.getCube().iterator(); i.hasNext(); k++) {
          if (k > 0) {
            int left = olap.getCube().size() - k + 1;
            out.println(", ...and " + left + " other Cube(s).");
            break;
          }
          Cube cube = (Cube) i.next();
          if (k > 0) {
            out.println(", ");
          }
          out.println(cube.getName());
          // only display for the first cube. otherwise,
          // the results could be too lengthy if there are
          // many cubes.
          if (k == 0) {
            // get measures of a cube.
            getMeasure(cube, out);
            // get CubeDimensionAssociations from cube.
            out.println("<h4>Dimensions retrieved with " +
              "cube.getCubeDimensionAssociation() and getDimension()</h4>");
            out.println("<table><tr><td class=\"single\">");
            int l = 0;
            for (Iterator j = cube.getCubeDimensionAssociation().iterator();
                 j.hasNext(); l++) {
              Dimension dimension = ((CubeDimensionAssociation) j.next()).
                getDimension();
              // display the dimension TaggedValues -
              // the fixed properties of a dimension.
              if (l > 0) {
                out.println(", ");
              }
              out.println(dimension.getName());
              if (l == 0) {
                out.println("<h4>First Dimension's TaggedValues</h4>");
                getTaggedValue(dimension, out);
                // get dynamic dimension properties
                out.println("<h4>First Dimension's Attributes</h4>");
                getProperty(dimension, out);
                // get hierarchies for the dimension.
                out.println("<h4>Hierarchies from Dimension</h4>");
                getHierarchy(dimension, out);
              }
            }
            out.println("</td></tr></table>");
          }
        }
        out.println("</td></tr></table>");
      }

      //*********************************************************
      // Retrieve metadata via ObjectFinder methods -
      // these methods provide the ability to retrieve a specific
      // object or set of objects.
      // Note that there are for each object type (such as Cube,
      // Dimension, and Hierarchy) always four find methods that
      // differ in their signatures:
      //  1. finder.findDimension
      //    (Cube cube,String dimensionName)
      //  2. finder.findDimensionFirst
      //       (Cube cube,String dimensionName)
      //  3. finder.findDimension
      //    (String schemaName, String cubeName,String dimensionName)
      //  4. finder.findDimensionFirst
      //    (String schemaName,String cubeName,String dimensionName)
      // The first two methods use a cube object and a
      // dimensionName to identify the dimension(s) to be found.
      // The findDimensionFirst() methods are simply for convenience;
      // it is equivalent to
      // (Dimension)finder.findDimension(cube,dimensionName)
      //       .get(0)
      Cube cube = null;
      Dimension dimension = null;
      {
        out.println("<br/><hr/>");
        out.println("<h3>Accessing metadata via object finder methods</h3>");
        IBIOlapObjectFinder finder = olap.getObjectFinder();

        // retrieve a specific cube
        cube = finder.findCubeFirst((String)null, "$0D_SD_C03");
        
        // This is just a sanity check to verify that the
        // cube on which this example relies was retrieved  
        if (cube==null){
            throw new BIException(Locale.getDefault(),
                                  Samples.SDK_SAMPLES_1000,
                                  new Object[] {"$0D_SD_C03"});
        }


        out.println("<h4>Find method findCube("+
          "String schemaname,String CubeName)</h4>");
        out.println("<h4>Found cube: </h4>");
        out.println("<table><tr><td class=\"single\">" + cube.getName() +
          "</td></tr></table>");

        // retrieve a specific dimension within this cube
        dimension = finder.findDimensionFirst(cube, "0D_COUNTRY");
        out.println("<h4>Find method findDimensionFirst(Cube cube," +
          "String dimensionName)</h4>");
        out.println("<h4>Found dimension: </h4>");
        out.println("<table><tr><td class=\"single\">" + dimension.getName() +
          "</td></tr></table>");

        // retrieve all hierarchies of a specific dimension
        out.println("<h4>Find method findHierarchy(Dimension dimension," +
          "String hierarchyName)</h4>");
        out.println("<h4>Found hierarchies</h4>");
        out.println("<table><tr><td class=\"single\">");
        LevelBasedHierarchy hierarchy = null;
        int k = 0;
        for (Iterator i = finder.findHierarchy(dimension, null).iterator();
             i.hasNext(); k++) {
          LevelBasedHierarchy levelBasedHierarchy =
            (LevelBasedHierarchy) i.next();
          if (k > 0) {
            out.println(", ");
          }
          out.println(levelBasedHierarchy.getName());
          if (levelBasedHierarchy.getName().equalsIgnoreCase("0D_COUNTRY")) {
            hierarchy = levelBasedHierarchy;
          }
        }
        out.println("</td></tr></table>");
      }

      //*********************************************************
      // Retrieve metadata via CWM-based JMI interfaces -
      // starting from the top level objects of the
      // OLAP Metadata Model, such as Cube, you can the use
      // the JMI interfaces provides by each object to "navigate"
      // to associated objects.  The code passage below shows how
      // to retrieve from a cube its associated dimensions, the
      // hierarchies of a given dimension, and the levels of a
      // given hierarchy. Note that in the OLAP package of the
      // CWM Metamodel, members are not directly associated with
      // levels. This is rooted in the considerably different
      // nature of members compared to other objects such as
      // cubes, dimensions, hierarchies and levels. Members
      // somehow straddle the line between data and metadata,
      // and in particular, members can potentially occur in
      // very large cardinalities. For example, a customer
      // dimension of a large retail
      // data warehouse may have millions of entries.
      // Heavy weight metadata objects are thus not suitable to
      // represent members.
      //*********************************************************
      Dimension countryDimension = null;
      {
        out.println("<br/><hr/>");
        out.println("<h3>Accessing metadata via JMI methods</h3>");
        // retrieve from a given cube its
        // CubeDimensionAssociations
        out.println("<h4>Iterating the Dimensions of a Cube via " +
          "Cube Dimension Associations</h4>");
        out.println("<table><tr><td class=\"single\">");
        int k = 0;
        for (Iterator i = cube.getCubeDimensionAssociation().iterator();
             i.hasNext(); k++) {
          dimension = ((CubeDimensionAssociation) i.next()).getDimension();
          if (k > 0) {
            out.println(", ");
          }
          out.println(dimension.getName());
          if (dimension.getName().equalsIgnoreCase("0D_COUNTRY")) {
            countryDimension = dimension;
          }
        }
        out.println("</td></tr></table>");
      }

      LevelBasedHierarchy countryHierarchy = null;
      {
        out.println("<h4>Iterating the Hierarchies of a Dimension</h4>");
        // retrieve from a dimension its hierarchies
        out.println("<table><tr><td class=\"single\">");
        int k = 0;
        for (Iterator i = countryDimension.getHierarchy().iterator();
             i.hasNext(); k++) {
          LevelBasedHierarchy levelBasedHierarchy =
            (LevelBasedHierarchy) i.next();
          if (k > 0) {
            out.println(", ");
          }
          out.println(levelBasedHierarchy.getName());
          if (levelBasedHierarchy.getName().equalsIgnoreCase("0D_COUNTRY")) {
            countryHierarchy = levelBasedHierarchy;
          }
        }
        out.println("</td></tr></table>");
      }

      Level level = null;
      {
        // retrieve from a hierarchy its levels
        out.println("<h4>Iterating the Levels of a Hierarchy via " +
          "Hierarchy Level Associations</h4>");
        out.println("<table><tr><td class=\"single\">");
        int k = 0;
        for (Iterator i = countryHierarchy.getHierarchyLevelAssociation().
             iterator(); i.hasNext(); k++) {
          level = ((HierarchyLevelAssociation) i.next()).getCurrentLevel();
          if (k > 0) {
            out.println(", ");
          }
          out.println(level.getName());
        }
        out.println("</td></tr></table>");
      }

      {
        // get the member data for a level
        out.println("<br/><hr/>");
        out.println("<h3>Accessing member data for a Level</h3>");
        IBIResultSet members = olap.getObjectFinder().findMemberData(
          Arrays.asList(new Object[] {level}), null);
        out.println("<table width=700 border=1 cellpadding=0 cellspacing=0>");
        out.println("<tr>");
        for (int i = 1; i <= members.getMetaData().getColumnCount(); i++) {
          out.println("<td class=\"headCenter\">");
          out.println(members.getMetaData().getColumnName(i));
          out.println("</td>");
        }
        out.println("</tr>");

        int k = 0;
        while (members.next()) {
          String style = (k & 1) == 0 ? "even" : "odd";
          out.println("<tr>");
          for (int i = 1; i <= members.getMetaData().getColumnCount(); i++) {
            out.println("<td class=\"" + style + "\">");
            out.println(members.getString(i));
            out.println("</td>");
          }
          out.println("</tr>");
          k++;
        }
        out.println("</table>");
      }

    } catch (Exception e) {
      // $JL-EXC$
      e.printStackTrace();
      if (e instanceof IBaseException)
        out.println("<p>Error: " +
                ((IBaseException)e).getNestedLocalizedMessage() + "</p>");
      else  
        out.println("<p>Error: " + e.getMessage() + "</p>");  
    }
    
    out.println("</body>");
    out.println("</html>");
  }

  public void destroy() {
  }

  private void getTaggedValue(ModelElement modelElement, PrintWriter out)
          throws BIResourceException {
    out.println("<table width=700 border=1 cellpadding=0 cellspacing=0>");
    int k = 0;
    for (Iterator i = olap.getTaggedValue(modelElement).iterator();
         i.hasNext(); k++) {
      String style = (k & 1) == 0 ? "even" : "odd";
      TaggedValue taggedValue = (TaggedValue) i.next();
      if (taggedValue != null) {
        out.println("<tr><td class=\"" + style + "\">" +
          taggedValue.getTag() + "</td>");
        out.println("<td class=\"" + style + "\">" +
          taggedValue.getValue() + "</td></tr>");
      }
    }
    out.println("</table>");
  }

  private void getHierarchy(Dimension dimension, PrintWriter out)
          throws BIResourceException {
    out.println("<table><tr><td class=\"single\">");
    int k = 0;
    for (Iterator i = dimension.getHierarchy().iterator(); i.hasNext(); k++) {
      LevelBasedHierarchy levelBasedHierarchy = (LevelBasedHierarchy) i.next();
      if (k > 0) {
        out.println(", ");
      }
      out.println(levelBasedHierarchy.getName());
      out.println("<h4>TaggedValue from Hierarchy</h4>");
      getTaggedValue(levelBasedHierarchy, out);
      getHla(levelBasedHierarchy, out);
    }
    out.println("</td></tr></table>");
  }

  private void getHla(LevelBasedHierarchy hierarchy, PrintWriter out) {
    out.println("<h4>Level retrieved with " +
      "hierarchy.getHierarchyLevelAssociation() and getCurrentLevel()</h4>");
    out.println("<table cellpadding=2 cellspacing=2><tr><td class=\"single\">");
    int k = 0;
    for (Iterator i = hierarchy.getHierarchyLevelAssociation().iterator();
         i.hasNext(); k++) {
      Level level = ((HierarchyLevelAssociation) i.next()).getCurrentLevel();
      if (k > 0) {
        out.println(", ");
      }
      out.println(level.getName());
    }
    out.println("</td></tr></table>");
  }

  private void getLevel(Dimension dimension, PrintWriter out)
          throws BIResourceException {
    out.println("<h4>Level from Dimension using " +
      "dimension.getMemberSelection</h4>");
    for (Iterator i = dimension.getMemberSelection().iterator(); i.hasNext();) {
      Level level = (Level) i.next();
      out.println("<h4>TaggedValues of Level " + level.getName() + "</h4>");
      getTaggedValue(level, out);
    }
  }

  //Dimension properties are getting from method getFeature().
  private void getProperty(Dimension dimension, PrintWriter out)
          throws BIResourceException {
    out.println("<h4>Dimension Attributes from dimension.getFeature()</h4>");
    out.println("<table cellpadding=2 cellspacing=2><tr><td class=\"single\">");
    int k = 0;
    for (Iterator i = dimension.getFeature().iterator(); i.hasNext(); k++) {
      Attribute attribute = (Attribute) i.next();
      if (k > 0) {
        out.println(", ");
      }
      out.println(attribute.getName());
      if (k == 0) {
        out.println("<h4>TaggedValues of Dimension Attribute</h4>");
        getTaggedValue(attribute, out);
      }
    }
    out.println("</td></tr></table>");
  }

  // Measure get from cube.
  private void getMeasure(Cube cube, PrintWriter out)
          throws BIResourceException {
    out.println("<h4>Measures of the Cube using cube.getFeature()</h4>");
    int k = 0;
    out.println("<table cellpadding=2 cellspacing=2><tr><td class=\"single\">");
    for (Iterator i = cube.getFeature().iterator(); i.hasNext(); k++) {
      Measure measure = (Measure) i.next();
      out.println(measure.getName() + ", ");
      if (k == 0) {
        out.println("<h4>TaggedValues of first Measure</h4>");
        getTaggedValue(measure, out);
      }
    }
    out.println("</td></tr></table>");
  }

  public static void main(String[] args) {
    if (args.length == 1) {
      MinimalServletContainer.executeServlet(new Olap_1(), args[0]);
    } else {
      MinimalServletContainer.executeServlet(new Olap_1(), System.out);
    }
  }

}