{"id":6857,"date":"2014-04-08T05:55:09","date_gmt":"2014-04-08T12:55:09","guid":{"rendered":"http:\/\/localhost\/exoblog\/?p=6857"},"modified":"2014-04-08T05:55:09","modified_gmt":"2014-04-08T12:55:09","slug":"crash-exo-platform-sizeof-jcr-content-command","status":"publish","type":"post","link":"https:\/\/www.exoplatform.com\/blog\/crash-exo-platform-sizeof-jcr-content-command\/","title":{"rendered":"Crash + eXo Platform \u2013 sizeOf JCR content command"},"content":{"rendered":"<blockquote><p>This guest post was adapted from an <a href=\"http:\/\/codercave.wordpress.com\/2014\/03\/13\/crash-exo-platform-sizeof-jcr-content-command\/\" target=\"_blank\" rel=\"noopener\">original article written in French by Stefan Letzner<\/a>.<\/p><\/blockquote>\n<p>Crash is a tool for connecting to a JVM and using all the libraries it loads to run Groovy scripts, browse the JCR, etc&#8230;<\/p>\n<p>This tool can operate in different ways:<\/p>\n<ul>\n<li>As a stantalone<\/li>\n<li>In web mode, deployed as a web app<\/li>\n<li>Directly injected by Spring<\/li>\n<\/ul>\n<p>In our case, we\u2019re going to use a <a href=\"https:\/\/code.google.com\/p\/crsh\/downloads\/detail?name=crash-1.2.8-gatein.tar.gz\" target=\"_blank\" rel=\"noopener\">web version<\/a> deployed in a Tomcat to get connected to the <a href=\"https:\/\/www.exoplatform.com\/\" target=\"_blank\" rel=\"noopener\">eXo Platform<\/a> JCR. Two versions of the web mode exist: one is configured to connect to eXo Platform while the other is more generic.<\/p>\n<p><!--more--><\/p>\n<h2>Getting started with Crash<\/h2>\n<p>At first we will see how to connect to Crash once it has been deployed in the eXo Platform Tomcat.<\/p>\n<p>By default, Crash listens to port 2000 for ssh and port 5000 for telnet. These are both available for connecting. In our case, we will connect via ssh, with the root user (password: gtn):<\/p>\n<pre class=\"lang:default decode:true \">ssh -p 2000 -l root localhost<\/pre>\n<p>where \u201clocalhost\u201d is the name of the server hosting the Tomcat.<\/p>\n<p>We then access the Crash command prompt:<\/p>\n<pre class=\"lang:default decode:true \">   ______\n .~      ~. |`````````,       .'.                   ..'''' |         |\n|           |'''|'''''      .''```.              .''       |_________|\n|           |    `.       .'       `.         ..'          |         |\n `.______.' |      `.   .'           `. ....''             |         | 1.2.8<\/pre>\n<p>Then, we need to connect to the repository:<\/p>\n<pre class=\"lang:default decode:true \">repo use container=portal<\/pre>\n<p>And connect to the workspace (here it is: &#8220;collaboration&#8221;):<\/p>\n<pre class=\"lang:default decode:true \">ws login -u root -p gtn collaboration<\/pre>\n<p>From here, we can navigate the JCR and do things with nodes such as creating, deleting and moving them.<\/p>\n<h2>Creating a new Crash command<\/h2>\n<p>A new command is created via a Groovy script.<\/p>\n<p>In the WAR, in WEB-INF there is a directory named crash\/commands. It has two directories for hosting Groovy scripts. The first contains general commands (system) and the second contains JCR commands.<\/p>\n<p>Then we create a Groovy script named \u201csizeof.groovy\u201d and move it into the JCR directory.<\/p>\n<p>New scripts and changes to existing scripts are hot deployed.<\/p>\n<p>This new command includes the options:<\/p>\n<p>-t (type): filters on \u201cjcr:primaryType\u201d<br \/>\n-l (limit): limits the number of results<br \/>\n-f (outPutFile): the path and name of the file of results<\/p>\n<p>and a mandatory parameter, \u201cjcr:path\u201d, which is the path from where we want to launch the research.<\/p>\n<p>Here is the script code:<\/p>\n<pre class=\"lang:default decode:true \">package crash.commands.jcr\n \nimport javax.jcr.query.Query\n \nimport org.crsh.text.ui.UIBuilder\nimport org.crsh.cli.Usage\nimport org.crsh.cli.Command\nimport org.crsh.cli.Man\nimport org.crsh.cli.Argument\nimport org.crsh.cli.Option\nimport org.crsh.cli.Required\n \n@Usage(\"sizeOf JCR nodes command\")\nclass sizeof extends org.crsh.jcr.command.JCRCommand {\n \n@Usage(\"size of a single content\")\n@Command\npublic Object list(\n@Option(names=[\"t\",\"type\"]) @Usage(\"jcr:primaryType\") String type,\n@Option(names=[\"l\",\"limit\"]) @Usage(\"the result limit\") @Man(\"The number of nodes displayed, by default this value is equals to 5\") Integer limit,\n@Option(names=[\"f\",\"outPutFile\"]) @Usage(\"Path with name of the output file\") String outPutFile,\n@Argument @Usage(\"JCR path\") String path) {\n \n    \/\/ Default limit set to 5\n    limit = limit ?: 5;\n \n    assertConnected();\n \n    def queryMgr = session.workspace.queryManager;\n \n    \/\/ JCR Query to retrieve all the subnodes of the given path\n    def statement = \"select * from \" + (type != null ? type : \"nt:base\") + \" where jcr:path like '\" + path + \"\/%'\";\n \n    \/\/ Exceution of the query\n    def select = queryMgr.createQuery(statement, Query.SQL);\n    def result = select.execute()\n    def nodes = result.nodes\n    def total = nodes.size\n \n    \/\/ output result\n    def stream = new StringBuilder()\n \n    def builder = new UIBuilder();\n    builder.node(\"The query matched \" + total + \" nodes\") {\n    def index = 0;\n    def contentMap = [:]\n \n    while (nodes.hasNext()) {\n      def n = nodes.next()\n      def nodeSize = 0\n \n      \/\/ calculate the node size\n      if (n.hasProperty(\"jcr:content\/jcr:data\")) {\n        nodeSize = n.getProperty(\"jcr:content\/jcr:data\").getLength() \/ 1024\n      }\n \n      contentMap.put(n.path,nodeSize)\n \n      index++\n      if (limit != null &amp;&amp; index &gt;= limit) {\n        break;\n      }\n    }\n \n    \/\/ Sort the new map from the biggest to the smallest\n    contentMap = contentMap.sort{a,b -&gt; b.value &lt;=&gt; a.value}\n    def chaine\n    def file\n \n    for (item in contentMap){\n      chaine = item.key + \" : \" + item.value + \" Ko\"\n      stream.append(chaine + \"\\r\\n\")\n      label(chaine)\n    }\n }\n \n \/\/ Store in the file\n if (outPutFile != null) {\n   System.out.println(\"Output file : \" + outPutFile)\n \n   file = new File(outPutFile)\n   file.write(stream.toString())\n }\n \n return builder;\n }\n}<\/pre>\n<p>Once the script has been deployed, we can use the \u201chelp\u201d command to ensure the script is properly available in Crash:<\/p>\n<pre class=\"lang:default decode:true \">% help\nTry one of these commands with the -h or --help switch:\n \nNAME DESCRIPTION\ncd : changes the current node\ncommit : saves changes\ncp : copy a node to another\ndashboard\nenv : display the term env\nfilter : A filter for a stream of map\nhelp : provides basic help\njava : various java language commands\njdbc : JDBC connection\njmx : Java Management Extensions\njndi : Java Naming and Directory Interface\njpa : Java persistance API\njvm : JVM informations\nlog : logging commands\nls : list the content of a node\nman : format and display the on-line manual pages\nmixin : mixin commands\nmv : move a node\nnode : node commands\npwd : print the current node path\nrepo : repository interaction commands\nrm : remove one or several node or a property\nrollback : ollback changes\nselec : execute a JCR sql query\nshell : shell related command\nsizeof : sizeOf JCR nodes command\nsleep : sleep for some time\nsort : Sort a map\nsystem : vm system properties commands\nthread : JVM thread commands\nversion : versioning commands\nws : workspace commands\nxpath : execute a JCR xpath query<\/pre>\n<p>Now, we can easily execute the following command:<\/p>\n<pre class=\"lang:default decode:true \">sizeof list -t nt:file -l 10 \"\/sites content\/live\/Contenus\/MonRepertoireDeContenus\"<\/pre>\n<p>In return, we\u2019ll get a table listing the content paths as well as their size, from the largest to the smallest.<\/p>\n<pre class=\"lang:default decode:true \">% sizeof content -t nt:file -l 10 \"\/sites content\/live\/Contenus\/Footer\nThe query matched 8 nodes\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer\/default.html : 2.556640625 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer-authentification\/default.html : 2.3564453125 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer\/js\/default.js : 0 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer-authentification\/js\/default.js : 0 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer\/css\/default.css : 0 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer\/medias\/images\/illustration : 0 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer-authentification\/css\/default.css : 0 Ko\n+-\/sites content\/live\/Contenus\/Footer\/Footer simple\/footer-authentification\/medias\/images\/illustration : 0 Ko<\/pre>\n<p>Crash is very well documented. You can find all the information you need on <a href=\"http:\/\/www.crashub.org\" target=\"_blank\" rel=\"noopener\">http:\/\/www.crashub.org<\/a><\/p>\n<p><b><a href=\"https:\/\/community.exoplatform.com\/portal\/dw\/\" target=\"_blank\" rel=\"noopener\">Join the eXo tribe<\/a> by registering for the community and access tutorials, support, and downloads!<\/b><\/p>\n<p><!--begin adv-events--><\/p>\n<div class=\"adv-events\" style=\"background: #476fad; padding: 30px 20px; color: white; border-radius: 3px;\">\n<div class=\"media\">\n<div class=\"media-body\">\n<h4 class=\"media-heading\">About Stefan Letzner<\/h4>\n<p>Stefan moved from web design to development and thus worked on many projects involving very different technologies: C#\/WPF, Java\/J2EE, JQuery, Groovy, Android&#8230;<\/p>\n<p>A developer at Capgemini since 2008, Stefan has worked on different projects, and he is very interested in open source environments. Recently, <b><a style=\"display: inline;\" href=\"http:\/\/codercave.wordpress.com\" target=\"_blank\" rel=\"noopener\">Stefan has been hosting a blog<\/a><\/b> which regroups code snippets, patterns and tips that are used on projects and that might need to be found quickly. It makes sure the knowledge is not lost.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!--end adv-events--><\/p>\n","protected":false},"excerpt":{"rendered":"This guest post was adapted from an original article written in French by Stefan Letzner. Crash is a tool for connecting to a JVM and using all the libraries it loads to run Groovy scripts, browse the JCR, etc&#8230; This tool can operate in different ways: As a stantalone In web mode, deployed as a [&hellip;]","protected":false},"author":95,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[699],"tags":[],"lang":"en","translations":{"en":6857},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/6857"}],"collection":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/users\/95"}],"replies":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/comments?post=6857"}],"version-history":[{"count":0,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/6857\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/media?parent=6857"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/categories?post=6857"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/tags?post=6857"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}