Package com.orientechnologies.orient.console

Source Code of com.orientechnologies.orient.console.OTableFormatter

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  *  you may not use this file except in compliance with the License.
  *  *  You may obtain a copy of the License at
  *  *
  *  *       http://www.apache.org/licenses/LICENSE-2.0
  *  *
  *  *  Unless required by applicable law or agreed to in writing, software
  *  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  *  See the License for the specific language governing permissions and
  *  *  limitations under the License.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */
package com.orientechnologies.orient.console;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.orientechnologies.common.collection.OMultiCollectionIterator;
import com.orientechnologies.common.console.OConsoleApplication;
import com.orientechnologies.common.util.OCallable;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
import com.orientechnologies.orient.core.db.record.ODatabaseRecordInternal;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.record.impl.ORecordBytes;

public class OTableFormatter {
  protected final static String       MORE            = "...";
  protected final static Set<String>  prefixedColumns = new HashSet<String>(Arrays.asList(new String[] { "#", "@RID" }));
  protected final OConsoleApplication out;
  protected final SimpleDateFormat    DEF_DATEFORMAT  = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
  protected int                       minColumnSize   = 4;
  protected int                       maxWidthSize    = 132;

  public OTableFormatter(final OConsoleApplication iConsole) {
    this.out = iConsole;
  }

  public void writeRecords(final Collection<OIdentifiable> resultSet, final int limit) {
    writeRecords(resultSet, limit, null);
  }

  public void writeRecords(final Collection<OIdentifiable> resultSet, final int limit,
      final OCallable<Object, OIdentifiable> iAfterDump) {
    final Map<String, Integer> columns = parseColumns(resultSet, limit);

    int fetched = 0;
    for (OIdentifiable record : resultSet) {
      dumpRecordInTable(fetched++, record, columns);
      if (iAfterDump != null)
        iAfterDump.call(record);

      if (limit > -1 && fetched >= limit) {
        printHeaderLine(columns);
        out.message("\nLIMIT EXCEEDED: resultset contains more items not displayed (limit=" + limit + ")");
        return;
      }
    }

    if (fetched > 0)
      printHeaderLine(columns);
  }

  public int getMaxWidthSize() {
    return maxWidthSize;
  }

  public OTableFormatter setMaxWidthSize(int maxWidthSize) {
    this.maxWidthSize = maxWidthSize;
    return this;
  }

  public void dumpRecordInTable(final int iIndex, final OIdentifiable iRecord, final Map<String, Integer> iColumns) {
    if (iIndex == 0)
      printHeader(iColumns);

    // FORMAT THE LINE DYNAMICALLY
    List<Object> vargs = new ArrayList<Object>();
    try {
      if (iRecord instanceof ODocument)
        ((ODocument) iRecord).setLazyLoad(false);

      final StringBuilder format = new StringBuilder(maxWidthSize);
      for (Entry<String, Integer> col : iColumns.entrySet()) {
        if (format.length() > 0)
          format.append('|');
        format.append("%-" + col.getValue() + "s");

        Object value = getFieldValue(iIndex, iRecord, col.getKey());

        if (value != null) {
          value = value.toString();
          if (((String) value).length() > col.getValue()) {
            // APPEND ...
            value = ((String) value).substring(0, col.getValue() - 3) + MORE;
          }
        }

        vargs.add(value);
      }

      out.message("\n" + format.toString(), vargs.toArray());

    } catch (Throwable t) {
      out.message("%3d|%9s|%s\n", iIndex, iRecord.getIdentity(), "Error on loading record dued to: " + t);
    }
  }

  private Object getFieldValue(final int iIndex, final OIdentifiable iRecord, final String iColumnName) {
    Object value = null;

    if (iColumnName.equals("#"))
      // RECORD NUMBER
      value = iIndex;
    else if (iColumnName.equals("@RID"))
      // RID
      value = iRecord.getIdentity().toString();
    else if (iRecord instanceof ODocument)
      value = ((ODocument) iRecord).field(iColumnName);
    else if (iRecord instanceof ORecordBytes)
      value = "<binary> (size=" + ((ORecordBytes) iRecord).toStream().length + " bytes)";
    else if (iRecord instanceof OIdentifiable) {
      final ORecord rec = iRecord.getRecord();
      if (rec instanceof ODocument)
        value = ((ODocument) rec).field(iColumnName);
      else if (rec instanceof ORecordBytes)
        value = "<binary> (size=" + ((ORecordBytes) rec).toStream().length + " bytes)";
    }

    if (value instanceof OMultiCollectionIterator<?>)
      value = "[" + ((OMultiCollectionIterator<?>) value).size() + "]";
    else if (value instanceof Collection<?>)
      value = "[" + ((Collection<?>) value).size() + "]";
    else if (value instanceof ORecord) {
      if (((ORecord) value).getIdentity().equals(ORecordId.EMPTY_RECORD_ID)) {
        value = ((ORecord) value).toString();
      } else {
        value = ((ORecord) value).getIdentity().toString();
      }
    } else if (value instanceof Date) {
      final ODatabaseRecordInternal db = ODatabaseRecordThreadLocal.INSTANCE.getIfDefined();
      if (db != null)
        value = db.getStorage().getConfiguration().getDateTimeFormatInstance().format((Date) value);
      else {
        value = DEF_DATEFORMAT.format((Date) value);
      }
    } else if (value instanceof byte[])
      value = "byte[" + ((byte[]) value).length + "]";

    return value;
  }

  private void printHeader(final Map<String, Integer> iColumns) {
    final StringBuilder buffer = new StringBuilder("\n");

    printHeaderLine(iColumns);
    int i = 0;
    for (Entry<String, Integer> column : iColumns.entrySet()) {
      if (i++ > 0)
        buffer.append('|');
      String colName = column.getKey();
      if (colName.length() > column.getValue())
        colName = colName.substring(0, column.getValue());
      buffer.append(String.format("%-" + column.getValue() + "s", colName));
    }
    out.message(buffer.toString());

    printHeaderLine(iColumns);
  }

  private void printHeaderLine(final Map<String, Integer> iColumns) {
    final StringBuilder buffer = new StringBuilder("\n");

    if (iColumns.size() > 0) {
      int i = 0;
      for (Entry<String, Integer> col : iColumns.entrySet()) {
        if (i++ > 0)
          buffer.append("+");

        for (int k = 0; k < col.getValue(); ++k)
          buffer.append("-");
      }
    }

    out.message(buffer.toString());
  }

  /**
   * Fill the column map computing the maximum size for a field.
   *
   * @param resultSet
   * @param limit
   * @return
   */
  private Map<String, Integer> parseColumns(final Collection<OIdentifiable> resultSet, final int limit) {
    final Map<String, Integer> columns = new LinkedHashMap<String, Integer>();

    for (String c : prefixedColumns)
      columns.put(c, minColumnSize);

    boolean tempRids = false;

    int fetched = 0;
    for (OIdentifiable id : resultSet) {
      ORecord rec = id.getRecord();

      for (String c : prefixedColumns)
        columns.put(c, getColumnSize(fetched, rec, c, columns.get(c)));

      if (rec instanceof ODocument) {
        ((ODocument) rec).setLazyLoad(false);
        // PARSE ALL THE DOCUMENT'S FIELDS
        ODocument doc = (ODocument) rec;
        for (String fieldName : doc.fieldNames()) {
          columns.put(fieldName, getColumnSize(fetched, doc, fieldName, columns.get(fieldName)));
        }
      } else if (rec instanceof ORecordBytes) {
        // UNIQUE BINARY FIELD
        columns.put("value", maxWidthSize - 15);
      }

      if (!tempRids && !rec.getIdentity().isPersistent())
        tempRids = true;

      if (limit > -1 && fetched++ >= limit)
        break;
    }

    if (tempRids)
      columns.remove("@RID");

    // COMPUTE MAXIMUM WIDTH
    int width = 0;
    for (Entry<String, Integer> col : columns.entrySet())
      width += col.getValue();

    if (width > maxWidthSize) {
      // SCALE COLUMNS AUTOMATICALLY
      final List<Map.Entry<String, Integer>> orderedColumns = new ArrayList<Map.Entry<String, Integer>>();
      orderedColumns.addAll(columns.entrySet());
      Collections.sort(orderedColumns, new Comparator<Map.Entry<String, Integer>>() {

        public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
          return o1.getValue().compareTo(o2.getValue());
        }
      });

      // START CUTTING THE BIGGEST ONES
      Collections.reverse(orderedColumns);
      while (width > maxWidthSize) {
        int oldWidth = width;

        for (Map.Entry<String, Integer> entry : orderedColumns) {
          final int redux = entry.getValue() * 10 / 100;

          if (entry.getValue() - redux < minColumnSize)
            // RESTART FROM THE LARGEST COLUMN
            break;

          entry.setValue(entry.getValue() - redux);

          width -= redux;
          if (width <= maxWidthSize)
            break;
        }

        if (width == oldWidth)
          // REACHED THE MINIMUM
          break;
      }

      // POPULATE THE COLUMNS WITH THE REDUXED VALUES
      columns.clear();
      for (String c : prefixedColumns)
        columns.put(c, minColumnSize);
      Collections.reverse(orderedColumns);
      for (Entry<String, Integer> col : orderedColumns)
        // if (!col.getKey().equals("#") && !col.getKey().equals("@RID"))
        columns.put(col.getKey(), col.getValue());

    }

    if (tempRids)
      columns.remove("@RID");

    return columns;
  }

  private Integer getColumnSize(final Integer iIndex, final ORecord iRecord, final String fieldName, final Integer origSize) {
    Integer newColumnSize;
    if (origSize == null)
      // START FROM THE FIELD NAME SIZE
      newColumnSize = fieldName.length();
    else
      newColumnSize = Math.max(origSize, fieldName.length());

    final Object fieldValue = getFieldValue(iIndex, iRecord, fieldName);

    if (fieldValue != null) {
      final String fieldValueAsString = fieldValue.toString();
      if (fieldValueAsString.length() > newColumnSize)
        newColumnSize = fieldValueAsString.length();
    }

    if (newColumnSize < minColumnSize)
      // SET THE MINIMUM SIZE
      newColumnSize = minColumnSize;

    return newColumnSize;
  }
}
TOP

Related Classes of com.orientechnologies.orient.console.OTableFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.