http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsole.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsole.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsole.scala deleted file mode 100644 index 57f79e0..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsole.scala +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands - -import org.apache.ignite.internal.GridProductImpl -import org.apache.ignite.internal.util.GridUtils -import org.apache.ignite.internal.util.typedef.internal.U -import org.apache.ignite.internal.util.scala.impl - -import org.apache.ignite.startup.cmdline.AboutDialog - -import javax.swing.ImageIcon -import java.awt.Image -import java.io.File -import java.text.SimpleDateFormat -import java.util - -import org.gridgain.visor.visor - -import scala.tools.jline.console.ConsoleReader -import scala.tools.jline.console.completer.Completer -import scala.tools.jline.internal.Configuration - -// Built-in commands. -// Note the importing of implicit conversions. -import org.gridgain.visor.commands.ack.VisorAckCommand -import org.gridgain.visor.commands.alert.VisorAlertCommand -import org.gridgain.visor.commands.cache.{VisorCacheClearCommand, VisorCacheCommand, VisorCacheCompactCommand, VisorCacheSwapCommand} -import org.gridgain.visor.commands.config.VisorConfigurationCommand -import org.gridgain.visor.commands.deploy.VisorDeployCommand -import org.gridgain.visor.commands.disco.VisorDiscoveryCommand -import org.gridgain.visor.commands.events.VisorEventsCommand -import org.gridgain.visor.commands.gc.VisorGcCommand -import org.gridgain.visor.commands.kill.VisorKillCommand -import org.gridgain.visor.commands.node.VisorNodeCommand -import org.gridgain.visor.commands.ping.VisorPingCommand -import org.gridgain.visor.commands.start.VisorStartCommand -import org.gridgain.visor.commands.tasks.VisorTasksCommand -import org.gridgain.visor.commands.top.VisorTopologyCommand -import org.gridgain.visor.commands.vvm.VisorVvmCommand - -/** - * Command line Visor. - */ -object VisorConsole extends App { - /** Version number. */ - private final val VISOR_VER = GridProductImpl.VER - - /** Release date. */ - private final val VISOR_RELEASE_DATE = GridProductImpl.RELEASE_DATE - - /** Copyright. */ - private final val VISOR_COPYRIGHT = GridProductImpl.COPYRIGHT - - /** Release date (another format). */ - private final val releaseDate = new SimpleDateFormat("ddMMyyyy").parse(VISOR_RELEASE_DATE) - - // Pre-initialize built-in commands. - VisorAckCommand - VisorAlertCommand - VisorCacheCommand - VisorCacheClearCommand - VisorCacheCompactCommand - VisorCacheSwapCommand - VisorConfigurationCommand - VisorDeployCommand - VisorDiscoveryCommand - VisorEventsCommand - VisorGcCommand - VisorKillCommand - VisorNodeCommand - VisorPingCommand - VisorTopologyCommand - VisorStartCommand - VisorTasksCommand - VisorVvmCommand - - // Setting up Mac OS specific system menu. - customizeUI() - - // Wrap line symbol for user input. - private val wrapLine = if (GridUtils.isWindows) "^" else "\\" - - private val emptyArg = "^([a-zA-z!?]+)$".r - private val varArg = "^([a-zA-z!?]+)\\s+(.+)$".r - - private var line: String = null - - private val buf = new StringBuilder - - private val reader = new ConsoleReader() - - reader.addCompleter(new VisorCommandCompleter(visor.commands)) - reader.addCompleter(new VisorFileNameCompleter()) - - welcomeMessage() - - private var ok = true - - while (ok) { - line = reader.readLine("visor> ") - - ok = line != null - - if (ok) { - line = line.trim - - if (line.endsWith(wrapLine)) { - buf.append(line.dropRight(1)) - } - else { - if (buf.size != 0) { - buf.append(line) - - line = buf.toString() - - buf.clear() - } - - try { - line match { - case emptyArg(c) => - visor.searchCmd(c) match { - case Some(cmdHolder) => cmdHolder.impl.invoke() - case _ => adviseToHelp(c) - } - case varArg(c, args) => - visor.searchCmd(c) match { - case Some(cmdHolder) => cmdHolder.impl.invoke(args.trim) - case _ => adviseToHelp(c) - } - case s if "".equals(s.trim) => // Ignore empty user input. - case _ => adviseToHelp(line) - } - } catch { - case ignore: Exception => ignore.printStackTrace() - } - } - } - } - - def terminalWidth() = reader.getTerminal.getWidth - - /** - * Prints standard 'Invalid command' error message. - */ - private def adviseToHelp(input: String) { - visor.warn( - "Invalid command name: '" + input + "'", - "Type 'help' to print commands list." - ) - } - - /** - * Print banner, hint message on start. - */ - private def welcomeMessage() { - visor.status() - - println("\nType 'help' for more information.") - println("Type 'open' to join the grid.") - println("Type 'quit' to quit form Visor console.") - - visor.nl() - } - - /** - * Setting up mac os specific menu. - */ - private def customizeUI() { - def urlIcon(iconPath: String) = { - val dockIconUrl = getClass.getResource(iconPath) - - assert(dockIconUrl != null, "Unknown icon path: " + iconPath) - - dockIconUrl - } - - try { - val appCls = Class.forName("com.apple.eawt.Application") - val aboutHndCls = Class.forName("com.apple.eawt.AboutHandler") - - val osxApp = appCls.getDeclaredMethod("getApplication").invoke(null) - - val dockIco = new ImageIcon(urlIcon("ggcube_node_128x128.png")) - - appCls.getDeclaredMethod("setDockIconImage", classOf[Image]).invoke(osxApp, dockIco.getImage) - - val bannerIconUrl = urlIcon("ggcube_node_48x48.png") - - val aboutHndProxy = java.lang.reflect.Proxy.newProxyInstance( - appCls.getClassLoader, - Array[Class[_]](aboutHndCls), - new java.lang.reflect.InvocationHandler { - def invoke(proxy: Any, mth: java.lang.reflect.Method, args: Array[Object]) = { - AboutDialog.centerShow("Visor - GridGain Shell Console", bannerIconUrl.toExternalForm, - VISOR_VER, releaseDate, VISOR_COPYRIGHT) - - null - } - }) - - appCls.getDeclaredMethod("setAboutHandler", aboutHndCls).invoke(osxApp, aboutHndProxy) - } - catch { - // Specifically ignore it here. - case _: Throwable => - } - } -} - -/** - * Visor command list completer. - * - * @param commands Commands list. - */ -private[commands] class VisorCommandCompleter(commands: Seq[String]) extends Completer { - import scala.collection.JavaConversions._ - - /** ordered commands. */ - private final val strings = new util.TreeSet[String](commands) - - @impl def complete(buf: String, cursor: Int, candidates: util.List[CharSequence]): Int = { - // buffer could be null - assert(candidates != null) - - if (buf == null) - candidates.addAll(strings) - else - strings.tailSet(buf).takeWhile(_.startsWith(buf)).foreach(candidates.add) - - if (candidates.size == 1) - candidates.set(0, candidates.get(0) + " ") - - if (candidates.isEmpty) -1 else 0 - } -} - -/** - * File path completer for different place of path in command. - */ -private[commands] class VisorFileNameCompleter extends Completer { - protected lazy val getUserHome = Configuration.getUserHome - - protected lazy val separator = File.separator - - @impl def complete(buf: String, cursor: Int, candidates: util.List[CharSequence]): Int = { - assert(candidates != null) - - var ixBegin = 0 - - // extracted path from buffer. - val path = buf match { - case null => "" - case emptyStr if emptyStr.trim == "" => "" - case str => - // replace wrong '/' on windows. - val translated = if (GridUtils.isWindows) str.replace('/', '\\') else str - - // line before cursor. - val left = translated.substring(0, cursor) - - // path begin marker. - val quote = if (left.count(_ == '\"') % 2 == 1) "\"" - else if (left.count(_ == '\'') % 2 == 1) "\'" - else "" - - val splitterSz = quote.size + " ".size - - // path begin marker index. - ixBegin = left.lastIndexOf(" " + quote) - ixBegin = if (ixBegin != -1) ixBegin + splitterSz else left.length - 1 - - // path end marker index. - var ixEnd = translated.indexOf(quote + " ", cursor) - ixEnd = if (ixEnd != -1) ixEnd - splitterSz else translated.length - - // extract path. - translated.substring(ixBegin, ixEnd) - } - - // resolve path - val file = resolvePath(path) - - // file dir and part of file name for complete. - val (dir, partOfName) = if (file.isDirectory) (file, "") else (file.getParentFile, file.getName) - - // filter all files in directory by part of file name. - if (dir != null && dir.listFiles != null) { - val files = for (file <- dir.listFiles if file.getName.startsWith(partOfName)) yield file - - if (files.size == 1) { - val candidate = files(0) - - if (candidate.isDirectory) separator else " " - - candidates.add(candidate.getName + (if (candidate.isDirectory) separator else " ")) - } - else - files.foreach(f => candidates.add(f.getName)) - } - - if (candidates.size > 0) ixBegin + path.lastIndexOf(separator) + separator.length else -1 - } - - /** - * Gets File representing the path passed in. First the check is made if path is in user home directory. - * If not, then the check is if path is absolute. - * If all checks fail, then related to the current dir File is returned. - * - * @param path - Path to resolve. - * @return Resolved path as File - */ - protected def resolvePath(path: String) = { - val homeDir = getUserHome - - val absFile = new File(path) - - // Special character: ~ maps to the user's home directory - if (path.startsWith("~" + separator)) - new File(homeDir.getPath, path.substring(1)) - else if (path.equals("~")) - homeDir.getParentFile - else if (absFile.exists() || absFile.getParentFile != null) // absolute path - absFile - else - new File(new File("").getAbsolutePath, path) - } -}
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsoleCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsoleCommand.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsoleCommand.scala deleted file mode 100644 index 571e80e..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorConsoleCommand.scala +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands - -import org.apache.ignite.internal.util.scala.impl - -import org.gridgain.visor.visor - -/** - * Command implementation. - */ -trait VisorConsoleCommand { - /** - * Command without arguments. - */ - def invoke() - - /** - * Command with arguments. - * - * @param args - arguments as string. - */ - def invoke(args: String) -} - -/** - * Singleton companion object. - */ -object VisorConsoleCommand { - /** - * Create `VisorConsoleCommand`. - * - * @param emptyArgs Function to execute in case of no args passed to command. - * @param withArgs Function to execute in case of some args passed to command. - * @return New instance of `VisorConsoleCommand`. - */ - def apply(emptyArgs: () => Unit, withArgs: (String) => Unit) = { - new VisorConsoleCommand { - @impl def invoke() = emptyArgs.apply() - - @impl def invoke(args: String) = withArgs.apply(args) - } - } - - /** - * Create `VisorConsoleCommand`. - * - * @param emptyArgs Function to execute in case of no args passed to command. - * @return New instance of `VisorConsoleCommand`. - */ - def apply(emptyArgs: () => Unit) = { - new VisorConsoleCommand { - @impl def invoke() = emptyArgs.apply() - - @impl def invoke(args: String) { - visor.warn( - "Invalid arguments for command without arguments.", - "Type 'help' to print commands list." - ) - } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorTextTable.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorTextTable.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorTextTable.scala deleted file mode 100644 index 2e53642..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/VisorTextTable.scala +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands - -import org.apache.ignite.internal.util.GridStringBuilder -import org.gridgain.visor.commands.VisorTextTable._ - -import scala.collection.Traversable - -/** - * ==Overview== - * Provides `ASCII`-based table with minimal styling support. - */ -class VisorTextTable { - /** - * Cell style. - */ - private sealed class Style( - var leftPad: Int = 1, // >= 0 - var rightPad: Int = 1, // >= 0 - var align: String = "center" // center, left, right - ) { - assert(leftPad >= 0) - assert(rightPad >= 0) - assert(align != null) - - /** - * Gets overall padding (left + right). - */ - def padding: Int = - leftPad + rightPad - } - - /** - * Cell style. - */ - private object Style { - /** - * - * @param sty Style. - */ - def apply(sty: String): Style = { - assert(sty != null) - - val cs = new Style - - if (!sty.isEmpty) { - for (e <- sty.split(',')) { - val a = e.split(":") - - assert(a.length == 2, "Invalid cell style: " + e.trim) - - val a0 = a(0).trim - val a1 = a(1).trim - - a0 match { - case "leftPad" => cs.leftPad = a1.toInt - case "rightPad" => cs.rightPad = a1.toInt - case "align" => cs.align = a1 - case _ => assert(false, "Invalid style: " + e.trim) - } - } - } - - cs - } - } - - /** - * Cell holder. - */ - private sealed case class Cell(style: Style, lines: Seq[String]) { - assert(style != null) - assert(lines != null) - - /** - * Cell's calculated width including padding. - */ - lazy val width = - if (height > 0) - style.padding + lines.max(Ordering.by[String, Int](_.length)).length - else - style.padding - - /** - * Gets height of the cell. - */ - def height: Int = lines.length - } - - /** - * Margin holder. - */ - private sealed case class Margin( - top: Int = 0, - right: Int = 0, - bottom: Int = 0, - left: Int = 0) { - assert(top >= 0) - assert(right >= 0) - assert(bottom >= 0) - assert(left >= 0) - } - - /** */ - private val NL = '\n' - - /** Headers. */ - private val hdr = collection.mutable.ArrayBuffer.empty[Cell] - - /** Rows. */ - private val rows = collection.mutable.ArrayBuffer.empty[Seq[Cell]] - - /** Current row, if any. */ - private var curRow: collection.mutable.ArrayBuffer[Cell] = null - - /** Table's margin, if any. */ - private var margin: Margin = Margin() - - /** Default row cell style, if any. */ - private var rowSty: String = "align:left" - - /** Default header cell style, if any. */ - private var hdrSty: String = "align:center" - - /** - * Flag indicating whether or not to draw inside horizontal lines - * between individual rows. - */ - var insideBorder = false - - /** - * Flag indicating whether of not to automatically draw horizontal lines - * for multiline rows. - */ - var autoBorder = true - - /** - * Maximum width of the cell. If any line in the cell exceeds this width - * it will be cut in two or more lines. - * - * '''NOTE''': it doesn't include into account the padding. Only the actual - * string length is counted. - */ - var maxCellWidth = Int.MaxValue - - /** - * - * @param ch Char. - * @param len Dash length. - */ - private def dash(ch: Char, len: Int): String = { - assert(len >= 0) - - new String().padTo(len, ch) - } - - /** - * - * @param s String. - * @param len Dash length. - */ - private def dash(s: String, len: Int): String = { - assert(len >= 0) - - var i = 0 - - val sb = new GridStringBuilder(s.length * len) - - while (i < len) { - sb.a(s) - - i += 1 - } - - sb.toString - } - - /** - * - * @param len Length. - */ - private def blank(len: Int): String = - dash(' ', len) - - /** - * Sets table's margin. - * - * @param top Top margin. - * @param right Right margin. - * @param bottom Bottom margin. - * @param left Left margin. - */ - def margin(top: Int = 0, right: Int = 0, bottom: Int = 0, left: Int = 0) { - assert(top >= 0) - assert(right >= 0) - assert(bottom >= 0) - assert(left >= 0) - - margin = Margin(top, right, bottom, left) - } - - /** - * Starts data row. - */ - def startRow() { - assert(curRow == null) - - curRow = collection.mutable.ArrayBuffer.empty[Cell] - } - - /** - * Ends data row. - */ - def endRow() { - assert(curRow.nonEmpty) - - rows += curRow - - curRow = null - } - - /** - * Adds row (one or more row cells). - * - * @param cells Row cells. For multi-line cells - use `Seq(...)`. - */ - def +=(cells: Any*): VisorTextTable = { - startRow() - - cells foreach { - case s: scala.collection.Iterable[Any] => addRowCell(s.toSeq: _*) - case p: Product => addRowCell(p.productIterator.toSeq: _*) - case a => addRowCell(a) - } - - endRow() - - this - } - - /** - * Adds header (one or more header cells). - * - * @param cells Header cells. For multi-line cells - use `Seq(...)`. - */ - def #=(cells: Any*): VisorTextTable = { - cells foreach { - case s: scala.collection.Iterable[Any] => addHeaderCell(s.toSeq: _*) - case p: Product => addHeaderCell(p.productIterator.toSeq: _*) - case a => addHeaderCell(a) - } - - this - } - - /** - * Adds single header cell. - * - * @param lines One or more cell lines. - */ - def addHeaderCell(lines: Any*): VisorTextTable = { - assert(lines != null) - assert(lines.length > 0) - - // Break up long line into multiple ones - if necessary. - val lst = lines flatten(_.toString.grouped(maxCellWidth)) - - hdr += Cell(Style(hdrSty), lst) - - this - } - - /** - * Gets current row style. - */ - def rowStyle = - rowSty - - /** - * Sets current row style. - * - * @param rowSty Row style to set. - */ - def rowStyle(rowSty: String) { - this.rowSty = rowSty - } - - /** - * Gets current header style. - */ - def headerStyle = - rowSty - - /** - * Sets current header style. - * - * @param hdrSty Header style to set. - */ - def headerStyle(hdrSty: String) { - this.hdrSty = hdrSty - } - - /** - * Adds single row cell. - * - * @param lines One or more row cells. Multiple lines will be printed on separate lines. - */ - def addRowCell(lines: Any*): VisorTextTable = { - assert(lines != null) - assert(lines.length >= 0) - assert(curRow != null) - - // Break up long line into multiple ones - if necessary. - val lst = lines flatten { - case it: Traversable[_] => it.flatten(_.toString.grouped(maxCellWidth)) - case null => Seq("") - case obj => obj.toString.grouped(maxCellWidth) - } - - curRow += Cell(Style(rowSty), lst) - - this - } - - /** - * - * @param txt Text to align. - * @param width Width already accounts for padding. - * @param sty Style. - */ - private def aligned(txt: String, width: Int, sty: Style): String = { - assert(txt != null) - assert(width > 0) - assert(sty != null) - assert(txt.length <= width) - - val d = width - txt.length - - val styTxt = txt - - sty.align.trim match { - case "center" => - blank(d / 2) + styTxt + blank(d / 2 + d % 2) - case "left" => - blank(sty.leftPad) + styTxt + blank(d - sty.leftPad) - case "right" => - blank(d - sty.rightPad) + styTxt + blank(sty.rightPad) - case _ => - throw new AssertionError("Invalid align option in: " + sty) - } - } - - /** - * Renders this table. - */ - def render() { - // Make sure table is not empty. - if (hdr.isEmpty && rows.isEmpty) - return - - var colsNum = -1 - - val isHdr = hdr.nonEmpty - - if (isHdr) - colsNum = hdr.size - - // Calc number of columns and make sure all rows are even. - for (r <- rows) - if (colsNum == -1) - colsNum = r.size - else if (colsNum != r.size) - assert(false, "Table with uneven rows.") - - assert(colsNum > 0) - - // At this point all rows in the table have the - // the same number of columns. - - val colWs = new Array[Int](colsNum) // Column widths. - val rowHs = new Array[Int](rows.length) // Row heights. - - // Header height. - var hdrH = 0 - - // Initialize column widths with header row (if any). - for (i <- 0 until hdr.size) { - val c = hdr(i) - - colWs(i) = c.width - - hdrH = math.max(hdrH, c.height) - } - - // Calc row heights and column widths. - for (i <- 0 until rows.length; j <- 0 until colsNum) { - val c = rows(i)(j) - - rowHs(i) = math.max(rowHs(i), c.height) - colWs(j) = math.max(colWs(j), c.width) - } - - // Table width without the border. - val tblW = colWs.sum + colsNum - 1 - - val tbl = new GridStringBuilder() - - // Top margin. - for (i <- 0 until margin.top) - tbl.a(" ").a(NL) - - // Print header, if any. - if (isHdr) { - tbl.a(blank(margin.left)).a(HDR_CRS).a(dash(HDR_HOR, tblW)).a(HDR_CRS).a(blank(margin.right)).a(NL) - - for (i <- 0 until hdrH) { - // Left margin and '|'. - tbl.a(blank(margin.left)).a(HDR_VER) - - for (j <- 0 until hdr.size) { - val c = hdr(j) - - if (i >= 0 && i < c.height) - tbl.a(aligned(c.lines(i), colWs(j), c.style)) - else - tbl.a(blank(colWs(j))) - - tbl.a(HDR_VER) // '|' - } - - // Right margin. - tbl.a(blank(margin.right)).a(NL) - } - - tbl.a(blank(margin.left)).a(HDR_CRS).a(dash(HDR_HOR, tblW)).a(HDR_CRS).a(blank(margin.right)).a(NL) - } - else - tbl.a(blank(margin.left)).a(ROW_CRS).a(dash(ROW_HOR, tblW)).a(ROW_CRS).a(blank(margin.right)).a(NL) - - // Print rows, if any. - if (rows.nonEmpty) { - val horLine = (i: Int) => { - // Left margin and '+' - tbl.a(blank(margin.left)).a(ROW_CRS) - - for (k <- 0 until rows(i).size) - tbl.a(dash(ROW_HOR, colWs(k))).a(ROW_CRS) - - // Right margin. - tbl.a(blank(margin.right)).a(NL) - } - - for (i <- 0 until rows.size) { - val r = rows(i) - - val rowH = rowHs(i) - - if (i > 0 && ((rowH > 1 && autoBorder) || insideBorder) && rowHs(i - 1) == 1) - horLine(i) - - for (j <- 0 until rowH) { - // Left margin and '|' - tbl.a(blank(margin.left)).a(ROW_VER) - - for (k <- 0 until r.size) { - val c = r(k) - val w = colWs(k) - - if (j < c.height) - tbl.a(aligned(c.lines(j), w, c.style)) - else - tbl.a(blank(w)) - - tbl.a(ROW_VER) // '|' - } - - // Right margin. - tbl.a(blank(margin.right)).a(NL) - } - - if (i < rows.size - 1 && ((rowH > 1 && autoBorder) || insideBorder)) - horLine(i) - } - - tbl.a(blank(margin.left)).a(ROW_CRS).a(dash(ROW_HOR, tblW)).a(ROW_CRS).a(blank(margin.right)).a(NL) - } - - // Bottom margin. - for (i <- 1 to margin.bottom) - tbl.a(" ").a(NL) - - print(tbl.toString) - } -} - -/** - * Static context. - */ -object VisorTextTable { - /** Table header horizontal line. */ - private val HDR_HOR = "=" - - /** Table header vertical line. */ - private val HDR_VER = "|" - - /** Table header crossroad line. */ - private val HDR_CRS = "+" - - /** Table row horizontal line. */ - private val ROW_HOR = '-' - - /** Table row vertical line. */ - private val ROW_VER = '|' - - /** Table row crossroad line. */ - private val ROW_CRS = "+" - - /** - * Creates new Visor text table. - */ - def apply() = - new VisorTextTable -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/Packet.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/Packet.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/Packet.scala deleted file mode 100644 index a598c45..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/Packet.scala +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands - -/** - * ==Overview== - * Visor 'ack' command implementation. - * - * ==Help== - * {{{ - * +-------------------------------------------+ - * | ack | Acks arguments on all remote nodes. | - * +-------------------------------------------+ - * }}} - * - * ====Specification==== - * {{{ - * ack {"s"} - * ack ("s", f) - * }}} - * - * ====Arguments==== - * {{{ - * s - * Optional string to print on each remote node. - * f - * Optional Scala predicate on 'ScalarRichNodePimp' filtering nodes in the topology. - * }}} - * - * ====Examples==== - * {{{ - * ack "Howdy!" - * Prints 'Howdy!' on all nodes in the topology. - * ack("Howdy!", _.id8.startsWith("123")) - * Prints 'Howdy!' on all nodes satisfying this predicate. - * ack - * Prints local node ID on all nodes in the topology. - * }}} - */ -package object ack http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/VisorAckCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/VisorAckCommand.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/VisorAckCommand.scala deleted file mode 100644 index f5a586f..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/ack/VisorAckCommand.scala +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands.ack - -import org.apache.ignite.internal.visor.misc.VisorAckTask - -import org.apache.ignite.cluster.ClusterGroupEmptyException - -import java.util.{HashSet => JavaHashSet} - -import org.gridgain.visor._ -import org.gridgain.visor.commands.VisorConsoleCommand -import org.gridgain.visor.visor._ - -import scala.collection.JavaConversions._ -import scala.language.implicitConversions - -/** - * ==Overview== - * Visor 'ack' command implementation. - * - * ==Help== - * {{{ - * +-------------------------------------------+ - * | ack | Acks arguments on all remote nodes. | - * +-------------------------------------------+ - * }}} - * - * ====Specification==== - * {{{ - * ack {"s"} - * ack ("s", f) - * }}} - * - * ====Arguments==== - * {{{ - * s - * Optional string to print on each remote node. - * f - * Optional Scala predicate on 'ScalarRichNodePimp' filtering nodes in the topology. - * }}} - * - * ====Examples==== - * {{{ - * ack "Howdy!" - * Prints 'Howdy!' on all nodes in the topology. - * ack("Howdy!", _.id8.startsWith("123")) - * Prints 'Howdy!' on all nodes satisfying this predicate. - * ack - * Prints local node ID on all nodes in the topology. - * }}} - */ -class VisorAckCommand { - /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - warn(errMsgs: _*) - warn("Type 'help ack' to see how to use this command.") - } - - /** - * ===Command=== - * Acks local node ID on all nodes. Note that this command - * behaves differently from its sibling that takes an argument. - * - * ===Example=== - * <ex>ack</ex> - * Prints local node IDs on all nodes in the topology. - */ - def ack() { - ack(null) - } - - /** - * ===Command=== - * Acks its argument on all nodes. - * - * ===Example=== - * <ex>ack "Howdy!"</ex> - * prints 'Howdy!' on all nodes in the topology. - * - * @param msg Optional command argument. If `null` this function is no-op. - */ - def ack(msg: String) { - if (!isConnected) - adviseToConnect() - else - try { - val nodeIds = grid.nodes().map(_.id()) - - grid.compute(grid.forNodeIds(nodeIds)) - .withName("visor-ack") - .withNoFailover() - .execute(classOf[VisorAckTask], toTaskArgument(nodeIds, msg)) - } - catch { - case _: ClusterGroupEmptyException => scold("Topology is empty.") - case e: Exception => scold("System error: " + e.getMessage) - } - } -} - -/** - * Companion object that does initialization of the command. - */ -object VisorAckCommand { - // Adds command's help to visor. - addHelp( - name = "ack", - shortInfo = "Acks arguments on all remote nodes.", - spec = Seq( - "ack", - "ack <message>" - ), - args = Seq( - "<message>" -> - "Optional string to print on each remote node." - ), - examples = Seq( - "ack" -> - "Prints local node ID on all nodes in the topology.", - "ack Howdy!" -> - "Prints 'Howdy!' on all nodes in the topology." - ), - ref = VisorConsoleCommand(cmd.ack, cmd.ack) - ) - - /** Singleton command. */ - private val cmd = new VisorAckCommand - - /** - * Singleton. - */ - def apply() = cmd - - /** - * Implicit converter from visor to commands "pimp". - * - * @param vs Visor tagging trait. - */ - implicit def fromAck2Visor(vs: VisorTag) = cmd -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/Packet.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/Packet.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/Packet.scala deleted file mode 100644 index 554565b..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/Packet.scala +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands - -/** - * ==Overview== - * Visor 'alert' command implementation. - * - * ==Help== - * {{{ - * +---------------------------------------------------------------------+ - * | alert | Generates email alerts for user-defined events. | - * | | Node events and grid-wide events are defined via mnemonics. | - * +---------------------------------------------------------------------+ - * }}} - * - * ====Specification==== - * {{{ - * alert - * alert "-u {-id=<alert-id>|-a}" - * alert "-r {-t=<sec>} -c1=e1<num> -c2=e2<num> ... -ck=ek<num>" - * }}} - * - * ====Arguments==== - * {{{ - * -u - * Unregisters alert(s). Either '-a' flag or '-id' parameter is required. - * Note that only one of the '-u' or '-r' is allowed. - * If neither '-u' or '-r' provided - all alerts will be printed. - * -a - * When provided with '-u' - all alerts will be unregistered. - * -id=<alert-id> - * When provided with '-u' - alert with matching ID will be unregistered. - * -r - * Register new alert with mnemonic predicate(s). - * Note that only one of the '-u' or '-r' is allowed. - * If neither '-u' or '-r' provided - all alerts will be printed. - * -t - * Defines notification frequency in seconds. Default is 15 minutes. - * This parameter can only appear with '-r'. - * -ck=ek<num> - * This defines a mnemonic for the metric that will be measured: - * Grid-wide metrics (not node specific): - * -cc Total number of available CPUs in the grid. - * -nc Total number of nodes in the grid. - * -hc Total number of physical hosts in the grid. - * -cl Current average CPU load (in %) in the grid. - * - * Per-node current metrics: - * -aj Active jobs on the node. - * -cj Cancelled jobs on the node. - * -tc Thread count on the node. - * -it Idle time on the node. - * Note: <num> can have 's', 'm', or 'h' suffix indicating - * seconds, minutes, and hours. By default (no suffix provided) - * value is assumed to be in milliseconds. - * -ut Up time on the node. - * Note: <num> can have 's', 'm', or 'h' suffix indicating - * seconds, minutes, and hours. By default (no suffix provided) - * value is assumed to be in milliseconds. - * -je Job execute time on the node. - * -jw Job wait time on the node. - * -wj Waiting jobs count on the node. - * -rj Rejected jobs count on the node. - * -hu Heap memory used (in MB) on the node. - * -cd Current CPU load on the node. - * -hm Heap memory maximum (in MB) on the node. - * - * Comparison part of the mnemonic predicate: - * =eq<num> Equal '=' to '<num>' number. - * =neq<num> Not equal '!=' to '<num>' number. - * =gt<num> Greater than '>' to '<num>' number. - * =gte<num> Greater than or equal '>=' to '<num>' number. - * =lt<num> Less than '<' to 'NN' number. - * =lte<num> Less than or equal '<=' to '<num>' number. - * - * NOTE: Email notification will be sent for the alert only when all - * provided mnemonic predicates evaluate to 'true'. - * }}} - * - * ====Examples==== - * {{{ - * alert - * Prints all currently registered alerts. - * alert "-u -a" - * Unregisters all currently registered alerts. - * alert "-u -id=12345678" - * Unregisters alert with provided ID. - * alert "-r -t=900 -cc=gte4 -cl=gt50" - * Notify every 15 min if grid has >= 4 CPUs and > 50% CPU load. - * }}} - */ -package object alert http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/VisorAlertCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/VisorAlertCommand.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/VisorAlertCommand.scala deleted file mode 100644 index 4c8bfeb..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/alert/VisorAlertCommand.scala +++ /dev/null @@ -1,839 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands.alert - -import org.apache.ignite.internal.util.lang.{GridFunc => F} - -import org.apache.ignite._ -import org.apache.ignite.cluster.ClusterNode -import org.apache.ignite.events.IgniteEventType._ -import org.apache.ignite.events.{IgniteDiscoveryEvent, IgniteEvent, IgniteEventType} -import org.apache.ignite.lang.IgnitePredicate - -import java.util.UUID -import java.util.concurrent.atomic._ - -import org.gridgain.visor._ -import org.gridgain.visor.commands.{VisorConsoleCommand, VisorTextTable} -import org.gridgain.visor.visor._ - -import scala.collection.immutable._ -import scala.language.implicitConversions -import scala.util.control.Breaks._ - -/** - * ==Overview== - * Visor 'alert' command implementation. - * - * ==Help== - * {{{ - * +---------------------------------------------------------------------+ - * | alert | Generates email alerts for user-defined events. | - * | | Node events and grid-wide events are defined via mnemonics. | - * +---------------------------------------------------------------------+ - * }}} - * - * ====Specification==== - * {{{ - * alert - * alert "-u {-id=<alert-id>|-a}" - * alert "-r {-t=<sec>} {-<metric>=<condition><value>} ... {-<metric>=<condition><value>}" - * }}} - * - * ====Arguments==== - * {{{ - * -u - * Unregisters alert(s). Either '-a' flag or '-id' parameter is required. - * Note that only one of the '-u' or '-r' is allowed. - * If neither '-u' or '-r' provided - all alerts will be printed. - * -a - * When provided with '-u' - all alerts will be unregistered. - * -id=<alert-id> - * When provided with '-u' - alert with matching ID will be unregistered. - * -r - * Register new alert with mnemonic predicate(s). - * Note that only one of the '-u' or '-r' is allowed. - * If neither '-u' or '-r' provided - all alerts will be printed. - * - * NOTE: Email settings can be specified in GridGain configu - * Email notification will be sent for the alert only - * provided mnemonic predicates evaluate to 'true'." - * -t - * Defines notification frequency in seconds. Default is 15 minutes. - * This parameter can only appear with '-r'. - * -<metric> - * This defines a mnemonic for the metric that will be measured: - * - * Grid-wide metrics (not node specific): - * cc - Total number of available CPUs in the grid. - * nc - Total number of nodes in the grid. - * hc - Total number of physical hosts in the grid. - * cl - Current average CPU load (in %) in the grid. - * - * Per-node current metrics: - * aj - Active jobs on the node. - * cj - Cancelled jobs on the node. - * tc - Thread count on the node. - * ut - Up time on the node. - * Note: <num> can have 's', 'm', or 'h' suffix indicating - * seconds, minutes, and hours. By default (no suffix provided) - * value is assumed to be in milliseconds. - * je - Job execute time on the node. - * jw - Job wait time on the node. - * wj - Waiting jobs count on the node. - * rj - Rejected jobs count on the node. - * hu - Heap memory used (in MB) on the node. - * cd - Current CPU load on the node. - * hm - Heap memory maximum (in MB) on the node. - * ), - * <condition> - * Comparison part of the mnemonic predicate: - * eq - Equal '=' to '<value>' number. - * neq - Not equal '!=' to '<value>' number. - * gt - Greater than '>' to '<value>' number. - * gte - Greater than or equal '>=' to '<value>' number. - * lt - Less than '<' to 'NN' number. - * lte - Less than or equal '<=' to '<value>' number. - * - * NOTE: Email notification will be sent for the alert only when all - * provided mnemonic predicates evaluate to 'true'. - * }}} - * - * ====Examples==== - * {{{ - * alert - * Prints all currently registered alerts. - * alert "-u -a" - * Unregisters all currently registered alerts. - * alert "-u -id=12345678" - * Unregisters alert with provided ID. - * alert "-r -t=900 -cc=gte4 -cl=gt50" - * Notify every 15 min if grid has >= 4 CPUs and > 50% CPU load. - * }}} - */ -class VisorAlertCommand { - /** Default alert frequency. */ - val DFLT_FREQ = 15L * 60L - - /** Alerts. */ - private var alerts = new HashMap[String, VisorAlert] - - /** Map of last sent notification per alert ID. */ - private var sent = new HashMap[(String, UUID), Long] - - /** Map of alert statistics. */ - private var stats = new HashMap[String, VisorStats] - - /** Last 10 sent alerts. */ - private var last10 = List.empty[VisorSentAlert] - - /** Subscribe guard. */ - private val guard = new AtomicBoolean(false) - - /** Node metric update listener. */ - private var lsnr: IgnitePredicate[IgniteEvent] = null - - /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - warn(errMsgs: _*) - warn("Type 'help alert' to see how to use this command.") - } - - /** - * ===Command=== - * Lists all registered alerts. - * - * ===Examples=== - * <ex>alert</ex> - * Prints all currently registered alerts. - */ - def alert() { - alert("") - } - - /** - * ===Command=== - * Registers, unregisters and list alerts. - * - * ===Examples=== - * <ex>alert "-u -a"</ex> - * Unregisters all currently registered alerts. - * - * <ex>alert "-i"</ex> - * Starts command in interactive mode. - * - * <ex>alert "-u -id=12345678"</ex> - * Unregisters alert with provided ID. - * - * <ex>alert "-r -t=900 -cc=gte4 -cl=gt50"</ex> - * Notify every 15 min if grid has >= 4 CPUs and > 50% CPU load. - * - * @param args Command arguments. - */ - def alert(args: String) { - assert(args != null) - - val argLst = parseArgs(args) - - if (hasArgFlag("u", argLst)) - unregisterAlert(argLst) - else if (hasArgFlag("r", argLst)) - registerAlert(argLst) - else if (args.length() > 0) - scold("Invalid arguments: " + args) - else - printAlerts() - } - - /** - * @param exprStr Expression string. - * @param f Node filter - * @param value Value generator. - */ - private def makeNodeFilter(exprStr: String, f: ClusterNode => Boolean, value: ClusterNode => Long): - ClusterNode => Boolean = { - assert(exprStr != null) - assert(f != null) - assert(value != null) - - val expr = makeExpression(exprStr) - - // Note that if 'f(n)' is false - 'value' won't be evaluated. - if (expr.isDefined) - (n: ClusterNode) => f(n) && expr.get.apply(value(n)) - else - throw new IgniteCheckedException("Invalid expression: " + exprStr) - } - - /** - * @param exprStr Expression string. - * @param f Grid filter - * @param value Value generator. - */ - private def makeGridFilter(exprStr: String, f: () => Boolean, value: () => Long): () => Boolean = { - assert(exprStr != null) - assert(f != null) - assert(value != null) - - val expr = makeExpression(exprStr) - - // Note that if 'f' is false - 'value' won't be evaluated. - if (expr.isDefined) - () => f() && expr.get.apply(value()) - else - throw new IgniteCheckedException("Invalid expression: " + exprStr) - } - - /** - * @param args Parsed argument list. - */ - private def registerAlert(args: ArgList) { - breakable { - assert(args != null) - - if (!isConnected) - adviseToConnect() - else { - // Warn but don't halt. - if (F.isEmpty(grid.configuration().getAdminEmails)) - warn("Admin emails are not configured (ignoring).") - else if (!grid.isSmtpEnabled) - warn("SMTP is not configured (ignoring).") - - val dfltNodeF = (_: ClusterNode) => true - val dfltGridF = () => true - - var nf = dfltNodeF - var gf = dfltGridF - - var freq = DFLT_FREQ - - try { - args foreach (arg => { - val (n, v) = arg - - n match { - // Grid-wide metrics (not node specific). - case "cc" if v != null => gf = makeGridFilter(v, gf, grid.metrics().getTotalCpus) - case "nc" if v != null => gf = makeGridFilter(v, gf, grid.metrics().getTotalNodes) - case "hc" if v != null => gf = makeGridFilter(v, gf, grid.metrics().getTotalHosts) - case "cl" if v != null => gf = makeGridFilter(v, gf, - () => (grid.metrics().getAverageCpuLoad * 100).toLong) - - // Per-node current metrics. - case "aj" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentActiveJobs) - case "cj" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentCancelledJobs) - case "tc" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentThreadCount) - case "ut" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getUpTime) - case "je" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentJobExecuteTime) - case "jw" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentJobWaitTime) - case "wj" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentWaitingJobs) - case "rj" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getCurrentRejectedJobs) - case "hu" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getHeapMemoryUsed) - case "hm" if v != null => nf = makeNodeFilter(v, nf, _.metrics().getHeapMemoryMaximum) - case "cd" if v != null => nf = makeNodeFilter(v, nf, - (n: ClusterNode) => (n.metrics().getCurrentCpuLoad * 100).toLong) - - // Other tags. - case "t" if v != null => freq = v.toLong - case "r" => () // Skipping. - case _ => throw new IgniteCheckedException("Invalid argument: " + makeArg(arg)) - } - }) - } - catch { - case e: NumberFormatException => - scold("Number conversion error: " + e.getMessage) - - break() - - case e: Exception => - scold(e.getMessage) - - break() - } - - if (nf == null && gf == null) { - scold("No predicates have been provided in args: " + makeArgs(args)) - - break() - } - - val alert = new VisorAlert( - id = id8, - nodeFilter = nf, - gridFilter = gf, - perNode = nf != dfltNodeF, - perGrid = gf != dfltGridF, - spec = makeArgs(args), - freq = freq, - createdOn = System.currentTimeMillis(), - varName = setVar(id8, "a") - ) - - // Subscribe for node metric updates - if needed. - registerListener() - - alerts = alerts + (alert.id -> alert) - stats = stats + (alert.id -> VisorStats()) - - // Set visor var pointing to created alert. - mset(alert.varName, alert.id) - - println("Alert '" + alert.id + "' (" + alert.varName + ") registered.") - } - } - } - - /** - * Registers node metrics update listener, if one wasn't registered already. - */ - private def registerListener() { - if (guard.compareAndSet(false, true)) { - assert(lsnr == null) - - lsnr = new IgnitePredicate[IgniteEvent] { - override def apply(evt: IgniteEvent): Boolean = { - val discoEvt = evt.asInstanceOf[IgniteDiscoveryEvent] - - val node = grid.node(discoEvt.eventNode().id()) - - if (node != null) - alerts foreach (t => { - val (id, alert) = t - - var nb = false - var gb = false - - try { - nb = alert.nodeFilter(node) - gb = alert.gridFilter() - } - catch { - // In case of exception (like an empty projection) - simply return. - case _: Throwable => return true - } - - if (nb && gb) { - val now = System.currentTimeMillis() - - val nKey = id -> node.id - val gKey = id -> null - - var go: Boolean = false - - if (nb && alert.perNode) - go = (now - sent.getOrElse(nKey, 0L)) / 1000 >= alert.freq - - if (!go && gb && alert.perGrid) - go = (now - sent.getOrElse(gKey, 0L)) / 1000 >= alert.freq - - if (go) { - // Update throttling. - if (nb && alert.perNode) - sent = sent + (nKey -> now) - - if (gb && alert.perGrid) - sent = sent + (gKey -> now) - - val stat: VisorStats = stats(id) - - assert(stat != null) - - // Update stats. - if (stat.firstSnd == 0) - stat.firstSnd = now - - stat.cnt += 1 - stat.lastSnd = now - - stats = stats + (id -> stat) - - // Send alert email notification. - sendEmail(alert, if (nb) Some(node) else None) - - // Write to Visor log if it is started (see 'log' command). - logText( - "Alert [" + - "id=" + alert.id + "(@" + alert.varName + "), " + - "spec=" + alert.spec + ", " + - "created on=" + formatDateTime(alert.createdOn) + - "]" - ) - - last10 = VisorSentAlert( - id = alert.id, - spec = alert.spec, - createdOn = alert.createdOn, - sentTs = now - ) +: last10 - - if (last10.size > 10) - last10 = last10.take(10) - } - } - }) - - true - } - } - - grid.events().localListen(lsnr, EVT_NODE_METRICS_UPDATED) - } - } - - /** - * Unregisters previously registered node metric update listener. - */ - private def unregisterListener() { - if (guard.compareAndSet(true, false)) { - assert(lsnr != null) - - assert(grid.events().stopLocalListen(lsnr)) - - lsnr = null - } - } - - /** - * Resets command. - */ - private def reset() { - unregisterAll() - unregisterListener() - } - - /** - * Sends email. - * - * @param a Alert to send email about. - * @param n `Option` for node. - */ - private def sendEmail(a: VisorAlert, n: Option[ClusterNode]) { - assert(a != null) - assert(n != null) - - val subj = "Visor alert triggered: '" + a.spec + '\'' - val headline = "GridGain ver. " + grid.product().version() - - val stat = stats(a.id) - - assert(stat != null) - - var body = - headline + NL + - NL + - "----" + NL + - "Alert ID: " + a.id + NL + - "Alert spec: " + a.spec + NL - - if (n.isDefined) - body += "Related node ID: " + n.get.id + NL + - "Related node addresses: " + n.get.addresses() + NL - - body += - "Send count: " + stat.cnt + NL + - "Created on: " + formatDateTime(a.createdOn) + NL + - "First send: " + (if (stat.firstSnd == 0) "n/a" else formatDateTime(stat.firstSnd)) + NL + - "Last send: " + (if (stat.lastSnd == 0) "n/a" else formatDateTime(stat.lastSnd)) + NL + - "----" + NL + - "Grid name: " + grid.name + NL - - body += - "----" + NL + - NL + - "NOTE:" + NL + - "This message is sent by Visor automatically to all configured admin emails." + NL + - "To change this behavior use 'adminEmails' grid configuration property." + NL + - NL + - "| www.gridgain.com" + NL + - "| supp...@gridgain.com" + NL - - // Schedule sending. - grid.sendAdminEmailAsync(subj, body, false) - } - - /** - * Prints advise. - */ - private def advise() { - println("\nType 'help alert' to see how to manage alerts.") - } - - /** - * Unregisters all alerts. - */ - private def unregisterAll() { - mclear("-al") - - alerts = new HashMap[String, VisorAlert] - } - - /** - * - * @param args Parsed argument list. - */ - private def unregisterAlert(args: ArgList) { - breakable { - assert(args != null) - - if (alerts.isEmpty) { - scold("No alerts have been registered yet.") - - break() - } - - // Unregister all alerts. - if (hasArgFlag("a", args)) { - unregisterAll() - - println("All alerts have been unregistered.") - } - // Unregister specific alert. - else if (hasArgName("id", args)) { - val idOpt = argValue("id", args) - - if (idOpt.isDefined) { - val id = idOpt.get - - val a = alerts.get(id) - - if (a.isDefined) { - alerts -= id - - // Clear variable host. - mclear(a.get.varName) - - println("Alert '" + id + "' unregistered.") - } - else { - scold("Failed to find alert with ID: " + id) - - break() - } - } - else { - scold("No value for '-id' parameter found.") - - break() - } - } - else { - scold("Failed to unregister alert.", "Either \"-a\" or \"-id\" parameter is required.") - - break() - } - - if (alerts.isEmpty) - unregisterListener() - } - } - - /** - * Prints out all alerts. - */ - private def printAlerts() { - if (alerts.isEmpty) - println("No alerts are registered.") - else { - println("Summary:") - - val sum = new VisorTextTable() - - val firstSnd = (-1L /: stats.values)((b, a) => if (b == -1) a.firstSnd else math.min(b, a.firstSnd)) - val lastSnd = (0L /: stats.values)((b, a) => math.max(b, a.lastSnd)) - - sum += ("Total alerts", alerts.size) - sum += ("Total sends", (0 /: stats.values)((b, a) => b + a.cnt)) - sum += ("First send", if (firstSnd == 0) "n/a" else formatDateTime(firstSnd)) - sum += ("Last send", if (lastSnd == 0) "n/a" else formatDateTime(lastSnd)) - - sum.render() - } - - if (last10.isEmpty) - println("\nNo alerts have been sent.") - else { - val last10T = VisorTextTable() - - last10T #= ("ID(@)", "Spec", "Sent", "Registered", "Count") - - last10.foreach((a: VisorSentAlert) => last10T += ( - a.idVar, - a.spec, - formatDateTime(a.sentTs), - formatDateTime(a.createdOn), - stats(a.id).cnt - )) - - println("\nLast 10 Triggered Alerts:") - - last10T.render() - } - - if (alerts.nonEmpty) { - val tbl = new VisorTextTable() - - tbl #= ("ID(@)", "Spec", "Count", "Registered", "First Send", "Last Send") - - val sorted = alerts.values.toSeq.sortWith(_.varName < _.varName) - - sorted foreach (a => { - val stat = stats(a.id) - - tbl += ( - a.id + "(@" + a.varName + ')', - a.spec, - stat.cnt, - formatDateTime(a.createdOn), - if (stat.firstSnd == 0) "n/a" else formatDateTime(stat.firstSnd), - if (stat.lastSnd == 0) "n/a" else formatDateTime(stat.lastSnd) - ) - }) - - println("\nAlerts: " + sorted.size) - - tbl.render() - - // Print advise. - advise() - } - } - - /** - * Gets unique ID8 id for the alert. - * - * @return 8-character locally unique alert ID. - */ - private def id8: String = { - while (true) { - val id = UUID.randomUUID().toString.substring(0, 8) - - // Have to check for guaranteed uniqueness. - if (!alerts.contains(id)) - return id - } - - assert(false, "Should never happen.") - - "" - } -} - -/** - * Visor alert. - */ -sealed private case class VisorAlert( - id: String, - nodeFilter: ClusterNode => Boolean, - gridFilter: () => Boolean, - freq: Long, - spec: String, - varName: String, - perNode: Boolean, - perGrid: Boolean, - createdOn: Long -) { - assert(id != null) - assert(spec != null) - assert(varName != null) -} - -/** - * Snapshot of the sent alert. - */ -private case class VisorSentAlert( - id: String, - sentTs: Long, - createdOn: Long, - spec: String -) { - assert(id != null) - assert(spec != null) - - def idVar: String = { - val v = mfind(id) - - if (v.isDefined) id + "(@" + v.get._1 + ")" else id - } -} - -/** - * Statistics holder for visor alert. - */ -sealed private case class VisorStats( - var cnt: Int = 0, - var firstSnd: Long = 0, - var lastSnd: Long = 0 -) - -/** - * Companion object that does initialization of the command. - */ -object VisorAlertCommand { - addHelp( - name = "alert", - shortInfo = "Email alerts for user-defined events.", - longInfo = Seq( - "Generates email alerts for user-defined events.", - "Node events and grid-wide events are defined via mnemonics." - ), - spec = Seq( - "alert", - "alert -u {-id=<alert-id>|-a}", - "alert -r {-t=<sec>} {-<metric>=<condition><value>} ... {-<metric>=<condition><value>}" - ), - args = Seq( - "-u" -> Seq( - "Unregisters alert(s). Either '-a' flag or '-id' parameter is required.", - "Note that only one of the '-u' or '-r' is allowed.", - "If neither '-u' or '-r' provided - all alerts will be printed." - ), - "-a" -> - "When provided with '-u' - all alerts will be unregistered.", - ("-id=<alert-id>", - "When provided with '-u' - alert with matching ID will be unregistered" + - "Note you can also use '@a0' ... '@an' variables as shortcut to <alert-id>."), - "-r" -> Seq( - "Register new alert with mnemonic predicate(s).", - "Note that only one of the '-u' or '-r' is allowed.", - "If neither '-u' or '-r' provided - all alerts will be printed.", - "", - "NOTE: Email settings can be specified in GridGain configuration file.", - " Email notification will be sent for the alert only when all", - " provided mnemonic predicates evaluate to 'true'." - ), - "-t" -> Seq( - "Defines notification frequency in seconds. Default is 15 minutes.", - "This parameter can only appear with '-r'." - ), - "-<metric>" -> Seq( - "This defines a mnemonic for the metric that will be measured:", - "", - "Grid-wide metrics (not node specific):", - " cc - Total number of available CPUs in the grid.", - " nc - Total number of nodes in the grid.", - " hc - Total number of physical hosts in the grid.", - " cl - Current average CPU load (in %) in the grid.", - "", - "Per-node current metrics:", - " aj - Active jobs on the node.", - " cj - Cancelled jobs on the node.", - " tc - Thread count on the node.", - " ut - Up time on the node.", - " Note: <num> can have 's', 'm', or 'h' suffix indicating", - " seconds, minutes, and hours. By default (no suffix provided)", - " value is assumed to be in milliseconds.", - " je - Job execute time on the node.", - " jw - Job wait time on the node.", - " wj - Waiting jobs count on the node.", - " rj - Rejected jobs count on the node.", - " hu - Heap memory used (in MB) on the node.", - " cd - Current CPU load on the node.", - " hm - Heap memory maximum (in MB) on the node." - ), - "<condition>" -> Seq( - "Comparison part of the mnemonic predicate:", - " eq - Equal '=' to '<value>' number.", - " neq - Not equal '!=' to '<value>' number.", - " gt - Greater than '>' to '<value>' number.", - " gte - Greater than or equal '>=' to '<value>' number.", - " lt - Less than '<' to 'NN' number.", - " lte - Less than or equal '<=' to '<value>' number." - ) - ), - examples = Seq( - "alert" -> - "Prints all currently registered alerts.", - "alert -u -a" -> - "Unregisters all currently registered alerts.", - "alert -u -id=12345678" -> - "Unregisters alert with provided ID.", - "alert -u -id=@a0" -> - "Unregisters alert with provided ID taken from '@a0' memory variable.", - "alert -r -t=900 -cc=gte4 -cl=gt50" -> - "Notify every 15 min if grid has >= 4 CPUs and > 50% CPU load." - ), - ref = VisorConsoleCommand(cmd.alert, cmd.alert) - ) - - /** Singleton command. */ - private val cmd = new VisorAlertCommand - - addCloseCallback(() => { - cmd.reset() - }) - - /** - * Singleton. - */ - def apply() = cmd - - /** - * Implicit converter from visor to commands "pimp". - * - * @param vs Visor tagging trait. - */ - implicit def fromAlert2Visor(vs: VisorTag): VisorAlertCommand = cmd -} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/Packet.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/Packet.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/Packet.scala deleted file mode 100644 index 7f7cb86..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/Packet.scala +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands - -/** - * ==Overview== - * Visor 'cache' command implementation. - * - * ==Help== - * {{{ - * +-----------------------------------------------------------------------------------------+ - * | cache | Prints statistics about caches from specified node on the entire grid. | - * | | Output sorting can be specified in arguments. | - * | | | - * | | Output abbreviations: | - * | | # Number of nodes. | - * | | H/h Number of cache hits. | - * | | M/m Number of cache misses. | - * | | R/r Number of cache reads. | - * | | W/w Number of cache writes. | - * +-----------------------------------------------------------------------------------------+ - * | cache -compact | Compacts all entries in cache on all nodes. | - * +-----------------------------------------------------------------------------------------+ - * | cache -clear | Clears all entries from cache on all nodes. | - * +-----------------------------------------------------------------------------------------+ - * | cache -scan | List all entries in cache with specified name. | - * +-----------------------------------------------------------------------------------------+ - * }}} - * - * ====Specification==== - * {{{ - * cache - * cache -i - * cache {-c=<cache-name>} {-id=<node-id>|id8=<node-id8>} {-s=lr|lw|hi|mi|re|wr} {-a} {-r} - * cache -clear {-c=<cache-name>} - * cache -compact {-c=<cache-name>} - * cache -scan -c=<cache-name> {-id=<node-id>|id8=<node-id8>} {-p=<page size>} - * }}} - * - * ====Arguments==== - * {{{ - * -id=<node-id> - * Full ID of the node to get cache statistics from. - * Either '-id8' or '-id' can be specified. - * If neither is specified statistics will be gathered from all nodes. - * -id8=<node-id> - * ID8 of the node to get cache statistics from. - * Either '-id8' or '-id' can be specified. - * If neither is specified statistics will be gathered from all nodes. - * -c=<cache-name> - * Name of the cache. - * -s=lr|lw|hi|mi|re|wr|cn - * Defines sorting type. Sorted by: - * lr Last read. - * lw Last write. - * hi Hits. - * mi Misses. - * rd Reads. - * wr Writes. - * If not specified - default sorting is 'lr'. - * -i - * Interactive mode. - * User can interactively select node for cache statistics. - * -r - * Defines if sorting should be reversed. - * Can be specified only with '-s' argument. - * -a - * Prints details statistics about each cache. - * By default only aggregated summary is printed. - * -compact - * Compacts entries in cache. - * -clear - * Clears cache. - * -scan - * Prints list of all entries from cache. - * -p=<page size> - * Number of object to fetch from cache at once. - * Valid range from 1 to 100. - * By default page size is 25. - * }}} - * - * ====Examples==== - * {{{ - * cache - * Prints summary statistics about all caches. - * cache -id8=12345678 -s=hi -r - * Prints summary statistics about caches from node with specified id8 - * sorted by number of hits in reverse order. - * cache -i - * Prints cache statistics for interactively selected node. - * cache -s=hi -r -a - * Prints detailed statistics about all caches sorted by number of hits in reverse order. - * cache -compact - * Compacts entries in interactively selected cache. - * cache -compact -c=cache - * Compacts entries in cache with name 'cache'. - * cache -clear - * Clears interactively selected cache. - * cache -clear -c=cache - * Clears cache with name 'cache'. - * cache -scan - * Prints list entries from interactively selected cache. - * cache -scan -c=cache - * Prints list entries from cache with name 'cache' from all nodes with this cache. - * cache -scan -c=@c0 -p=50 - * Prints list entries from cache with name taken from 'c0' memory variable - * with page of 50 items from all nodes with this cache. - * cache -scan -c=cache -id8=12345678 - * Prints list entries from cache with name 'cache' and node '12345678' ID8. - * }}} - */ -package object cache http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/VisorCacheClearCommand.scala ---------------------------------------------------------------------- diff --git a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/VisorCacheClearCommand.scala b/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/VisorCacheClearCommand.scala deleted file mode 100644 index 2ea3100..0000000 --- a/modules/visor-console/src/main/scala/org/gridgain/visor/commands/cache/VisorCacheClearCommand.scala +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -package org.gridgain.visor.commands.cache - -import org.apache.ignite.internal.visor.cache.VisorCacheClearTask -import org.apache.ignite.internal.visor.util.VisorTaskUtils._ - -import org.apache.ignite.cluster.ClusterNode - -import java.util.Collections - -import org.gridgain.visor.commands.VisorTextTable -import org.gridgain.visor.visor._ - -import scala.collection.JavaConversions._ -import scala.language.reflectiveCalls -import scala.util.control.Breaks._ - -/** - * ==Overview== - * Visor 'clear' command implementation. - * - * ==Help== - * {{{ - * +------------------------------------------------------------+ - * | cache -clear | Clears all entries from cache on all nodes. | - * +------------------------------------------------------------+ - * }}} - * - * ====Specification==== - * {{{ - * cache -clear - * cache -clear -c=<cache-name> - * }}} - * - * ====Arguments==== - * {{{ - * <cache-name> - * Name of the cache. - * If not specified, default cache will be cleared. - * }}} - * - * ====Examples==== - * {{{ - * cache -clear - * Clears interactively selected cache. - * cache -clear -c=cache - * Clears cache with name 'cache'. - * }}} - */ -class VisorCacheClearCommand { - /** - * Prints error message and advise. - * - * @param errMsgs Error messages. - */ - private def scold(errMsgs: Any*) { - assert(errMsgs != null) - - warn(errMsgs: _*) - warn("Type 'help cache' to see how to use this command.") - } - - /** - * ===Command=== - * Clears cache by its name. - * - * ===Examples=== - * <ex>cache -clear -c=cache</ex> - * Clears cache with name 'cache'. - * - * @param argLst Command arguments. - */ - def clear(argLst: ArgList, node: Option[ClusterNode]) = breakable { - val cacheArg = argValue("c", argLst) - - val cacheName = cacheArg match { - case None => null // default cache. - - case Some(s) if s.startsWith("@") => - warn("Can't find cache variable with specified name: " + s, - "Type 'cache' to see available cache variables." - ) - - break() - - case Some(name) => name - } - - val prj = if (node.isDefined) grid.forNode(node.get) else grid.forCache(cacheName) - - if (prj.nodes().isEmpty) { - val msg = - if (cacheName == null) - "Can't find nodes with default cache." - else - "Can't find nodes with specified cache: " + cacheName - - scold(msg).^^ - } - - val t = VisorTextTable() - - t #= ("Node ID8(@)", "Entries Cleared", "Cache Size Before", "Cache Size After") - - val cacheSet = Collections.singleton(cacheName) - - prj.nodes().foreach(node => { - val res = grid.compute(grid.forNode(node)) - .withName("visor-cclear-task") - .withNoFailover() - .execute(classOf[VisorCacheClearTask], toTaskArgument(node.id(), cacheSet)) - .get(cacheName) - - t += (nodeId8(node.id()), res.get1() - res.get2(), res.get1(), res.get2()) - }) - - println("Cleared cache with name: " + escapeName(cacheName)) - - t.render() - } -} - -/** - * Companion object that does initialization of the command. - */ -object VisorCacheClearCommand { - /** Singleton command. */ - private val cmd = new VisorCacheClearCommand - - /** - * Singleton. - */ - def apply() = cmd -}