Useful groovy scripts for SAP hybris Commerce. Part 1

The Groovy console is a very handy tool to develop and run scripts inside hybris without touching the source code. It is a very powerful tool for debugging purposes, especially if you need to troubleshoot the remote system. In this article, I collected some of the scripts I use regularly in my work. 

This is a PART 1 of the series. Today I share the following Groovy scripts:

  • Display any file on the server
  • Execute a command
  • Show last N lines from the console log
  • Execute a flexible search query
  • Execute a raw SQL query
  • Retrieve an item by PK
  • Modifying objects
  • Removing items
  • Sending data by e-mail
  • Importing IMPEX
  • Print all properties of an object
  • Print all methods of an object
  • Print the hybris type tree
  • Print hybris type stats

Display any file on the server

It may help you if you have no access to the environment (besides /hac), but you need to get some info from the local file system.

new File('/etc/passwd').eachLine {
    println it
}

2017-11-29_14h33_07

Execute a command

println "ls -la".execute().text

Show last N lines from the console log

println "tail -n 50 ../../../../log/tomcat/console.log".execute().text

Keep in mind that you will be able to see only the local logs. In the well-configured cluster environment, the storefront logs are not available from the host where hac is accessible.

2017-11-29_14h36_47.png

Execute a Flexible Search query

flexibleSearchService = spring.getBean("flexibleSearchService");
    query = "select {pk} from {Category}";
result = flexibleSearchService.search(query);
  itempk = "";
  for (item in result.getResult()) {
      println item.getName();
  }

2017-11-29_14h37_15

Retrieve an item by PK

import de.hybris.platform.core.PK;
Long examplePK = ...;
object = modelService.get(new PK(examplePK));
print object.getPk();
print ", ";
println object.getName();

2017-11-29_14h39_25

Execute a raw SQL query

The following code may not work with hybris 6.5 because of the HAC classes are not available from Groovy.

import de.hybris.platform.hac.data.dto.SqlSearchResultData;
import de.hybris.platform.hac.facade.impl.DefaultFlexibleSearchFacade;

SqlSearchResultData searchResult;
query =
  "select  createdTS, modifiedTS, PK, p_uid,  p_name, p_catalogVersion,  p_visible from cmscomponent limit 0,10";
  ;
flexibleSearchFacade = new DefaultFlexibleSearchFacade();
result = flexibleSearchFacade.executeRawSql(query, 2000000, false);

println result.getHeaders().join("\t");

for (item in result.getResultList()) {
  println (item.join("\t"));
}

Due to the tab-delimited, the output can be easily copied to Excel via copy-paste (Chrome->Notepad, Notepad->Excel).

2017-11-24_02h55_16

2017-11-24_02h58_42

If you need to process some specific fields differently (for example, extract the data from the model), you can collect field names and add the custom code inside the second loop. In the next example, I also demonstrate how to use modelService for resolving PKs.

import de.hybris.platform.hac.data.dto.SqlSearchResultData;
import de.hybris.platform.hac.facade.impl.DefaultFlexibleSearchFacade;
import de.hybris.platform.core.PK;

SqlSearchResultData searchResult;
query =
  "select  *  from users limit 0,2";
  ;
flexibleSearchFacade = new DefaultFlexibleSearchFacade();
result = flexibleSearchFacade.executeRawSql(query, 2000000, false);

modelService = spring.getBean("modelService");

for (item in result.getResultList()) {
  columnsCounter=0;
  for (fieldValue in item) {
  fieldName = result.getHeaders()[columnsCounter++];

  if (fieldName == "PK") {
    print modelService.get(new PK(fieldValue as Long)).getName() + "\t";

  if (fieldName == "TypePkString") {
    print modelService.get(new PK(fieldValue as Long)).getName() + "\t";
  } 

  }
  println "";
}

2017-11-24_03h16_16

Modifying objects

import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
flexibleSearchService = spring.getBean("flexibleSearchService")
mimeService = spring.getBean("mimeService")
modelService = spring.getBean("modelService")
def findMediasWithoutMime() {
	query = "SELECT {PK} FROM {Media} WHERE {mime} IS NULL")
	flexibleSearchService.search(query).result;
}
findMediasWithoutMime().each {
	it.mime = mimeService.getMimeFromFileExtension(it.realfilename)
	modelService.save(it)
}

Removing items

 flexibleSearchService.search("select {pk} from {product} where ....").result.each {
   modelService.remove(it)
 }

Sending data by e-mail

// Create a temporary file for the demo
 file = File.createTempFile("stuff",".tmp")
 file.deleteOnExit()
 pw = new PrintWriter(file)
 pw.println 'This is line 1'
 pw.println 'This is line 2'
 pw.close()

 // Create the email
 email = de.hybris.platform.util.mail.MailUtils.getPreConfiguredEmail()
 email.addTo('r.aliev@gmail.com')
 email.subject = 'Important stuff attached'
 email.msg = 'Here is your attachment'

 // Create an attachment that is our temporary file
 attachment = new org.apache.commons.mail.EmailAttachment();
 attachment.path = file.absolutePath
 attachment.disposition = org.apache.commons.mail.EmailAttachment.ATTACHMENT
 attachment.description = 'Stuff'
 attachment.name = 'stuff.txt'

 // Attach the attachment
 email.attach(attachment)

 // Send the email
 email.send()

 // Clean up
 file.delete()

*The code above may not work with some configurations.

Importing IMPEX

If you have an access to the Groovy Script console, you are definetely have an access to Impex Import. However, for some tasks, the impex script itself is dynamic and created dynamically. For these tasks, the following code can be useful:

import de.hybris.platform.util.CSVConstants
import de.hybris.platform.servicelayer.impex.ImpExResource
import de.hybris.platform.servicelayer.impex.ImportResult
import de.hybris.platform.servicelayer.impex.impl.StreamBasedImpExResource

importImpex("INSERT Language;isocode;active\n;test;true")

def importImpex(String content) {
    final ImpExResource mediaRes = new StreamBasedImpExResource(new ByteArrayInputStream(content.getBytes()), CSVConstants.HYBRIS_ENCODING)
    importService.importData(mediaRes)
}

Print all properties of an object

result = spring.getBean("flexibleSearchService").search("select {pk} from {Language}")
// properties
result.properties.each { println "$it.key -> $it.value" }

2017-11-29_14h45_03

Print all methods of an object

a = spring.getBean("flexibleSearchService").search("select {pk} from {Language}");
dumpOut a
def dumpOut( clz ) {
  clz.metaClass.methods.each { method ->
    println "${method.returnType.name} ${method.name}( ${method.parameterTypes*.name.join( ', ' )} )"
  }
}

Show the hybris type tree

import java.util.*;
flexibleSearch = spring.getBean("flexibleSearchService")
result = flexibleSearch.search (/select {pk} from {ComposedType}/).getResult()
Tree tree = new Tree();
result.each {
  Node node = new Node(it.getCode(), it.getSuperType()?.getCode());
  type = it.getClass().getSimpleName();
  type = type.replace("ComposedTypeModel", "<Composed>");
  type = type.replace("RelationMetaTypeModel", "<Relation>");
  type = type.replace("EnumerationMetaTypeModel", "<ENUM>");
  type = type.replace("TypeModel", "");
  node.setDetails(type);
  tree.getElements().add(node);
}

for (element in tree.getElements()) {
   node1 = tree.find(element.getValue());
   node2 = tree.find(element.getParentValue());
   if (node1 != null) { node1.setParent(node2); }
   if (node2 != null) { node2.addChild(node1); }
   if (element.getParentValue() == null) { root = node1; }
}

int level = 0;
printANode(0, root);
displaySubTree(tree, level, root);

void printANode(level, Node item) {
  print "."*level;
  println item.getValue() + "(" + item.getDetails() + ")";
}

void displaySubTree(Tree tree, int level, Node node)
{
  List<Node> subItems = node.getChildren();
  for (item in subItems) {
      printANode(level+1, item);
      displaySubTree(tree, level+1, item);
  }
}

public class Tree
{
   List<Node> elements;
  public List<Node> getElements() { return elements; }
  public Tree() {
       elements = new ArrayList();
   }
   public void add (Node element) {
      elements.add(element);
   }

    public Node find(String value) {
      for (it in elements) { if (it.getValue() == value) { return it; } }
    }
}

public class Node
{
    private Node parent = null;
    private List<Node> children = null;
    private String details = "";
    private String value = "";
    private String parentValue = "";    

    public Node(String value, String parent)
    {
        this.children = new ArrayList<>();
        this.value = value;
        this.parentValue = parent;
    }

    public setDetails(String nodeDetails)
    {
        details = nodeDetails;
    }
    public getDetails() { return details; }

    public List<Node> getChildren() {
       return children;
    }

    public void addChild(Node child)
    {
        children.add(child);
        child.addParent(this);
    }
    public addParent (Node parentNode)
    {

        parent = parentNode;
    }
    public getValue () {
        return value;
    }
    public String getParentValue() {
        return parentValue;
    }
    public setParent(Node node)
    {
        parent = node;
    }
}

2017-11-29_14h46_16

*The screenshot above shows only composed types for the sake of simplicity.

Print hybris type stats

The following code prints a number of items for each hybris type.

import java.util.*;
import java.lang.*;
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery
import de.hybris.platform.hac.facade.impl.DefaultFlexibleSearchFacade;
import de.hybris.platform.servicelayer.search.SearchResult;

flexibleSearch = spring.getBean("flexibleSearchService")
flexibleSearchFacade = new DefaultFlexibleSearchFacade();
typeService = spring.getBean("typeService");

result = flexibleSearch.search (/select {pk} from {ComposedType}/).getResult()
Tree tree = new Tree();
result.each {
  Node node = new Node(it.getCode(), it.getSuperType()?.getCode());
  type = it.getClass().getSimpleName();
  isabstract = it.getAbstract() ? "<abstract>":"";
  isjaloonly = it.getJaloonly() ? "<jaloonly>":"";
  type = type.replace("ComposedTypeModel", "<Composed>");
  type = type.replace("RelationMetaTypeModel", "<Relation>");
  type = type.replace("EnumerationMetaTypeModel", "<ENUM>");
  type = type.replace("TypeModel", "");
  node.setDetails(type+isabstract+isjaloonly);
  tree.getElements().add(node);
}

for (element in tree.getElements()) {
   node1 = tree.find(element.getValue());
   node2 = tree.find(element.getParentValue());
   if (node1 != null) { node1.setParent(node2); }
   if (node2 != null) { node2.addChild(node1); }
   if (element.getParentValue() == null) { root = node1; }
}

displaySubTree(tree, 0, root, root.getValue());

void printANode(level, Node item, String history) {
  count = "-";

  if (!item.getNotLeaf() && !item.getDetails().contains("<abstract>")
      && !item.getDetails().contains("<jaloonly>")) {
        count = calculateCount(item.getValue())
  }

  println history + "\t" + item.getValue() + "(" + item.getDetails() + ") \t"+count;

}

void displaySubTree(Tree tree, int level, Node node, String history)
{
  List<Node> subItems = node.getChildren();
  if (subItems.size() == 0) {
      printANode(level, node, history);
  }
  for (item in subItems) {
      printANode(level+1, item, history );
      if (item.getChildren().size() != 0) {
        displaySubTree(tree, level+1, item, history + "=>" + item.getValue());
      }
  }
}

public class Tree
{
   List<Node> elements;
  public List<Node> getElements() { return elements; }
  public Tree() {
       elements = new ArrayList();
   }
   public void add (Node element) {
      elements.add(element);
   }

    public Node find(String value) {
      for (it in elements) { if (it.getValue() == value) { return it; } }
    }
}

public class Node
{
    private Node parent = null;
    private List<Node> children = null;
    private String value;
    private String details = "";
    private String parentValue = "";
    private Boolean notLeaf = false;

    public Node(String value, String parent)
    {
        this.children = new ArrayList<>();
        this.value = value;
        this.parentValue = parent;
    }

    public setNotLeaf(Boolean itIsNotALeaf) {
        notLeaf = itIsNotALeaf;
    }
    public getNotLeaf(Boolean itIsNotALeaf) {
        return notLeaf;
    }

    public List<Node> getChildren() {
       return children;
    }

    public void addChild(Node child)
    {
        children.add(child);
        child.addParent(this);
    }
    public addParent (Node parentNode)
    {
        parent = parentNode;
    }
    public getValue () {
        return value;
    }
    public String getParentValue() {
        return parentValue;
    }
    public setParent(Node node)
    {
        parent = node;
    }
    public getParent()
    {
        return parent;
    }
      public setDetails(String nodeDetails)
    {
        details = nodeDetails;
    }
    public getDetails() { return details; }
}

String calculateCount(component) {
  query = "select count({pk}) from {"+component+"}";
  FlexibleSearchQuery fquery = new FlexibleSearchQuery(query);
  fquery.setResultClassList(Arrays.asList(String.class));
  fquery.setCount(1);
  SearchResult<String> result = flexibleSearch.search(fquery);
    return (result.getResult()?.get(0));
 }

2017-11-29_19h55_35

There are three columns: path, object and count. The count shows how many objects of the type is in the database. The script displays the tab-separated data. In order to get the table as shown above, copy the text to Notepad first (to get rid of formatting) and then from Notepad to Excel spreadsheet.

One comment

  1. great, thanks for sharing

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: