Setting Up Terminal 🖥️ for Development on MacOS (Updated 2025)

If you’re setting up your MacBook for development, having a well-configured terminal is essential. This guide will walk you through installing and configuring a powerful terminal setup using Homebrew, iTerm2, and Oh My Zsh, along with useful plugins.

1. Install Homebrew

Homebrew is a package manager that simplifies installing software on macOS.

Open the Terminal and run:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

After installation, add Homebrew to your PATH by running the following commands:

echo >> ~/.zprofile
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

Verify installation:

brew --version

Check here.

2. Install iTerm2

The default macOS Terminal is functional but lacks advanced features. iTerm2 is a powerful alternative.

Install it using Homebrew:

brew install --cask iterm2

Open iTerm2 from your Applications folder after installation.

Check and Install Git

Ensure Git is installed:

git --version

If not installed, install it using Homebrew:

brew install git

3. Install Oh My Zsh

Oh My Zsh enhances the Zsh shell with themes and plugins. Install it with:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Check here.

Configure .zshrc

Edit your .zshrc file:

vim ~/.zshrc

Add useful plugins:

plugins=(git rails ruby)

The default theme is robbyrussell. You can explore other themes here.

Customize iTerm2 Color Scheme

Find and import themes from iTerm2 Color Schemes.

4. Add Zsh Plugins

Enhance your terminal experience with useful plugins.

a. Install zsh-autosuggestions

This plugin provides command suggestions as you type.

Install via Oh My Zsh:

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

Or install via Homebrew:

brew install zsh-autosuggestions

Add to ~/.zshrc:

plugins=(git rails ruby zsh-autosuggestions)

If installed via Homebrew, add:

source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh

to the bottom of ~/.zshrc.

Restart iTerm2:

exec zsh

b. Install zsh-syntax-highlighting

This plugin highlights commands to distinguish valid syntax from errors.

Install via Oh My Zsh:

git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting

Add to .zshrc:

plugins=(git rails ruby zsh-autosuggestions zsh-syntax-highlighting)

Restart iTerm2:

exec zsh

Wrapping Up

Your terminal is now set up for an optimized development experience! With Homebrew, iTerm2, Oh My Zsh, and useful plugins, your workflow will be faster and more efficient.

to be continued …

Senior-Level Linux Commands Every Backend Engineer Should Know

For a senior backend engineer, Linux commands are more than tools for navigating directories.

They become a production debugging language.

When a Rails application is consuming too much memory, a log contains millions of lines, a deployment introduces unexpected configuration changes, or a background worker suddenly starts failing, knowing how to combine commands such as sed, awk, grep, find, xargs, sort, uniq, cut, tr, jq, and ps can save hours.

The real skill is not memorizing commands. It is understanding how to compose them into pipelines.

command1 | command2 | command3

This article focuses on commands and techniques that become particularly valuable at a senior engineering level.


1. grep – Search With Intent

Most developers know:

grep "ERROR" production.log

But grep becomes much more powerful with regular expressions and recursive searches.

Search recursively

grep -R "ActiveRecord::Deadlocked" log/

Useful when you don’t know which file contains the problem.

Ignore case

grep -Ri "timeout" .

Show line numbers

grep -n "connection refused" production.log

Search multiple patterns

grep -E "ERROR|FATAL|Exception" production.log

Show context around matches

grep -C 5 "NoMethodError" production.log

This is extremely useful for application logs because the surrounding lines often contain request IDs, parameters, stack traces, or timestamps.

When to use

Use grep when your primary operation is:

“Find lines matching this condition.”

2. sed – Stream Editing

sed is one of the most useful Linux commands for manipulating text without opening an editor.

The simplest example:

sed 's/foo/bar/g' file.txt

Replace every foo with bar.

Delete lines

Delete empty lines:

sed '/^$/d' file.txt

Delete lines containing DEBUG:

sed '/DEBUG/d' production.log

Print specific lines

sed -n '100,150p' production.log

This displays lines 100 through 150.

Very useful when investigating a specific portion of a huge log file.

Modify a configuration file

For example:

sed -i 's/RAILS_LOG_LEVEL=info/RAILS_LOG_LEVEL=debug/' .env

-i modifies the file in place.

Be careful with production configuration files. Prefer making a backup when appropriate:

sed -i.bak 's/old_value/new_value/g' config.yml

Advanced use: remove sensitive information

Suppose logs contain email addresses:

User login: john@example.com
User login: alice@example.com

We can mask them:

sed -E 's/[[:alnum:]._%+-]+@[[:alnum:].-]+\.[A-Za-z]{2,}/[REDACTED]/g' app.log

This is useful when sanitizing logs before sharing them.

When to use sed

Think:

“I want to transform or filter text while streaming it.”

3. awk – Lightweight Data Processing

awk is one of the most important commands for senior engineers.

It treats input as structured columns.

Suppose:

101 John 4500
102 Alice 6000
103 Bob 5000

Run:

awk '{print $1, $3}' users.txt

Output:

101 4500
102 6000
103 5000

Filter records

awk '$3 > 5000 {print $1, $2, $3}' users.txt

Now only users earning more than 5000 are printed.

Calculate values

awk '{sum += $3} END {print sum}' users.txt

Calculate the total salary.

Average:

awk '{sum += $3; count++} END {print sum/count}' users.txt

Processing logs

Imagine an Nginx log:

10.0.0.1 GET /users 200
10.0.0.2 GET /users 500
10.0.0.3 GET /products 200
10.0.0.4 GET /users 500

Extract HTTP status:

awk '{print $4}' access.log

Count status codes:

awk '{print $4}' access.log | sort | uniq -c

Result:

2 200
2 500

awk with conditions

awk '$4 >= 500 {print}' access.log

Find server errors.

When to use awk

Think:

“My input has columns/records and I need to filter, transform, aggregate, or calculate something.”

For quick operational data analysis, awk can often replace writing a small script.

4. cut – Extract Columns

For simple column extraction, cut is usually easier than awk.

Example:

cut -d',' -f1 users.csv

Extract the first CSV field.

Multiple fields:

cut -d',' -f1,3 users.csv

Character ranges:

cut -c1-10 file.txt

Use cut when the operation is straightforward.

Use awk when logic becomes conditional or computational.

5. sort + uniq – Finding Patterns

These commands become extremely powerful together.

Suppose you want to find the most common URLs:

awk '{print $7}' access.log |
sort |
uniq -c |
sort -nr

Example:

1500 /api/users
980 /api/orders
450 /health

This is a classic production-analysis pipeline.

Why sort before uniq?

uniq only detects adjacent duplicate lines.

Therefore:

sort file.txt | uniq

is usually required.

6. head and tail – Inspect Large Files Safely

Instead of opening a 10 GB log:

head -n 50 production.log

Last 100 lines:

tail -n 100 production.log

The real power is:

tail -f production.log

Follow new log entries in real time.

For Rails applications this is particularly useful during deployments:

tail -f log/production.log

You can combine it with grep:

tail -f production.log | grep --line-buffered "ERROR"

Now you’re effectively monitoring errors as they occur.

7. find – Locate Files Precisely

Find Ruby files:

find app/ -type f -name "*.rb"

Find files modified recently:

find log/ -type f -mtime -1

Find large files:

find /var/log -type f -size +500M

Find and execute a command:

find tmp/ -type f -name "*.tmp" -delete

Be careful with destructive commands.

A safer approach is:

find tmp/ -type f -name "*.tmp" -print

Inspect the result first.

8. xargs – Turn Output Into Arguments

Suppose:

find tmp/ -type f -name "*.tmp"

returns many files.

You can pass them to another command:

find tmp/ -type f -name "*.tmp" -print0 |
xargs -0 rm

-print0 and -0 are important because filenames can contain spaces or special characters.

Another example:

grep -Rl "TODO" app/ | xargs wc -l

This finds files containing TODO and counts their lines.

9. ps – Understand Running Processes

For a Rails server:

ps aux | grep puma

More useful:

ps aux --sort=-%mem | head

Find processes consuming the most memory.

CPU:

ps aux --sort=-%cpu | head

This can quickly identify runaway workers.

10. top and htop – Live System Diagnosis

top

For an easier interactive interface:

htop

Use these when diagnosing:

  • High CPU
  • Memory pressure
  • Load
  • Runaway processes
  • Number of workers
  • Process states

For application debugging, don’t look only at Rails logs. Always correlate application behavior with OS-level resource usage.

11. df vs du

These commands answer different questions.

Disk filesystem usage

df -h

Answers:

How full is the filesystem?

Directory usage

du -sh log/

Answers:

What is consuming the space?

Find the largest directories:

du -sh * | sort -hr | head

This is extremely useful when a server suddenly reports:

No space left on device

12. lsof – Discover Who Owns a Resource

Find which process is using port 3000:

lsof -i :3000

Find processes using a file:

lsof /var/log/production.log

Find deleted files still consuming disk:

lsof +L1

This last one is particularly valuable.

A process may keep a deleted log file open. du may not show the file anymore, while disk space remains consumed until the process releases it.

13. ss – Network Investigation

Modern Linux systems commonly use ss for socket inspection.

Check listening ports:

ss -lntp

Check established connections:

ss -nt

Find connections to port 5432:

ss -nt | grep ':5432'

This can help investigate:

  • PostgreSQL connection exhaustion
  • Unexpected network connections
  • Services not listening
  • Connection buildup

14. jq – JSON From the Command Line

Modern APIs produce JSON everywhere.

Suppose:

{
"users": [
{"id": 1, "name": "John"},
{"id": 2, "name": "Alice"}
]
}

Extract names:

jq '.users[].name' response.json

Output:

"John"
"Alice"

Transform it:

jq -r '.users[] | "\(.id),\(.name)"' response.json

This becomes especially powerful when debugging APIs:

curl -s https://example.com/api/users |
jq '.users[] | select(.active == true)'

15. curl – API Debugging From the Shell

Instead of immediately reaching for Postman:

curl -i https://example.com/health

POST JSON:

curl -X POST https://example.com/api/users \
-H "Content-Type: application/json" \
-d '{"name":"John"}'

Measure request timing:

curl -o /dev/null -s \
-w 'HTTP: %{http_code}\nTime: %{time_total}s\n' \
https://example.com

This is extremely useful when debugging production APIs.

16. tee – See and Save Output Simultaneously

bundle exec rails db:migrate 2>&1 | tee migration.log

The output is displayed on the terminal while simultaneously being written to a file.

Useful during deployments and troubleshooting.

17. Powerful Pipelines

The real senior-level skill comes from combining commands.

For example, identify the most frequent 500 responses:

grep " 500 " access.log |
awk '{print $7}' |
sort |
uniq -c |
sort -nr |
head -20

Or find the largest log files:

find /var/log -type f -size +100M -print |
xargs -r ls -lh |
sort -k5 -hr

Or monitor Rails errors:

tail -f log/production.log |
grep --line-buffered -E "ERROR|FATAL|Exception"

18. A Practical Senior Engineer Mental Model

Instead of memorizing hundreds of commands, categorize them.

RequirementCommands
Searchgrep, rg
Transform textsed
Process columns/dataawk, cut
Count/group datasort, uniq
Locate filesfind
Connect commandsxargs, pipes
Inspect processesps, top, htop
Inspect disksdf, du
Inspect socketsss, lsof
JSON processingjq
HTTP/API debuggingcurl
Save + display outputtee

The most important progression is:

Basic Linux
Individual commands
Pipelines
Conditional filtering
Aggregation
Production diagnosis

A senior engineer should be comfortable turning an unclear operational question into a shell pipeline.

For example:

“Which API endpoints are causing the most HTTP 500 errors right now?”

Instead of manually opening a log file, you should naturally arrive at something like:

grep " 500 " access.log |
awk '{print $7}' |
sort |
uniq -c |
sort -nr |
head -20

That is the real power of Linux:

small, composable tools solving complex operational problems.

For Rails engineers especially, mastering these commands means you can diagnose the application, process, filesystem, network, and logs from the same shell instead of relying entirely on application-level tooling.

Happy commanding!

Setup Zsh, NVM, Rbenv | Moving micro-services into AWS EC2 instance – Part 2

In this post let’s continue to install the other packages.

Install Oh my zsh.

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
sudo reboot

Make sure that ~/.zshrc contains the following lines.

# Path to your oh-my-zsh installation.
export ZSH="$HOME/.oh-my-zsh"

# See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes
ZSH_THEME="robbyrussell"

# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(git)

source $ZSH/oh-my-zsh.sh

# Rbenv Loader
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"

# NVM loader
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

Install NVM

sudo apt-get update -y
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
source ~/.bashrc or source ~/.zshrc

Install Rbenv

git clone https://github.com/rbenv/rbenv.git ~/.rbenv

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc # OR
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.zshrc

echo 'eval "$(rbenv init -)"' >> ~/.bashrc # OR
echo 'eval "$(rbenv init -)"' >> ~/.zshrc

source ~/.bashrc # OR
source ~/.zshrc

type rbenv # to see if rbenv is installed correctly

In this tutorial, we installed nvm to manage Node versions, rbenv to manage Ruby versions and gemsets, and Oh My Zsh for a better terminal interface with more information. As a result, we use the .zshrc file instead of the .bashrc file on this machine.

To load all the necessary configurations into the terminal, add the above lines of code for nvm and rbenv to the zshrc file.

Basic Software installation| Moving micro-services into AWS EC2 instance – Part 1

As I mentioned in the previous post, I have decided to move away from micro-services. To achieve this, I am taking an AWS EC2 instance and configuring each micro-service on this instance. For this setup, I am using an Ubuntu 16.04 machine because my application setup is a bit old. However, if you have newer versions of Rails, Ruby, etc., you may want to choose Ubuntu 20.04.

Our setup includes Ruby on Rails (5.2.1) micro-services (5-10 in number), a NodeJS application, a Sinatra Application, and an Angular 9.1 Front-End Application.

To begin, go to the AWS EC2 home page and select an Ubuntu 16.04 machine with default configurations and SSH enabled.

https://ap-south-1.console.aws.amazon.com/ec2/v2/home

Now login to this new instance and install all the packages we needed for our setup.

Software Installation

Update the package list.

sudo apt-get update

Install Ruby dependencies.

sudo apt-get install ruby-dev
sudo apt-get install libxml2-dev
sudo apt-get install libxslt-dev
sudo apt-get install graphviz

Install NodeJS

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs
node -v

Install yarn and other dependencies.

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install git-core zlib1g-dev build-essential libssl-dev libreadline-dev libyaml-dev libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev libcurl4-openssl-dev software-properties-common libffi-dev nodejs yarn

Install Mysql 5.7 (Remember this is for Ubuntu 16.04, 18.04 versions)

sudo apt-get install mysql-server-5.7 mysql-client-core-5.7 libmysqlclient-dev
sudo service mysql status # or
systemctl status mysql
username: <your-username>, password: <your-password>

You can also try
mysql_secure_installation, if you use other mysql version.

Note that if you are setting up Ubuntu 20.04, there is a significant change in MySQL, as the version of MySQL is now 8.0 instead of 5.7. If you have applications running in MySQL 5.7, it is recommended that you set up and use Ubuntu 16.04 or 18.04.

We will continue the installation process in our next post.

Our Challenges with Microservices on AWS ECS

As part of our startup, our predecessors chose to use micro-services for our new website as it is a trending technology.

This decision has many benefits, such as:

  • Scaling a website becomes much easier when using micro-services, as each service can be scaled independently based on its individual needs.
  • The loosely coupled nature of micro-services also allows for easier development and maintenance, as changes to one service do not affect the functionality of other services.
  • Additionally, deployment can be focused on each individual service, making the overall process more efficient.
  • Micro-services also allow for the use of different technologies for each service, providing greater flexibility and the ability to choose the best tools for each task.
  • Finally, testing can be concentrated on one service at a time, allowing for more thorough and effective testing, which can result in higher quality code and a better user experience.

In developing our application with micro-services, we considered the potential problems that we may face in the future. However, it is important to note that we also need to consider whether these problems will have a significant impact compared to the potential disadvantages of using micro-services.

One factor to keep in mind is that our website is currently experiencing low traffic and we are acquiring clients gradually. As such, we need to consider whether the benefits of micro-services outweigh any potential drawbacks for our particular situation.

Regardless, some potential issues with micro-services include increased complexity and overhead in development, as well as potential performance issues when integrating multiple services. Additionally, managing multiple services and ensuring they communicate effectively can also be a challenge.

Despite the benefits of micro-services, we have faced some issues in implementing them. One significant challenge is the increased complexity of deployment and maintenance that comes with having multiple services. This can require more time and resources to manage and can potentially increase the likelihood of errors.

Additionally, the cost of using AWS ECS for hosting all of the micro-services can be higher than using other hosting solutions for a less traffic website. This is something to consider when weighing the benefits and drawbacks of using micro-services for our specific needs.

Another challenge we have faced is managing dependencies between services, which can be difficult to avoid. When one service goes offline, it can cause issues with other services, leading to a “No Service” issue on the website.

Finally, it can be very difficult to go back to a monolithic application even if we combine 3-4 services together, as they may use different software or software versions. This can make it challenging to make changes or updates to the application as a whole.

It is important to carefully consider whether micro-service architecture is the best fit for your business and current situation. If you have a less used website or are just starting your business, it may not be necessary or cost-effective to implement micro-services.

It is important to take the time to evaluate the benefits and drawbacks of using micro-services for your specific needs and budget. Keep in mind that hosting multiple micro-services can come with additional costs, so be prepared to pay a minimum amount for hosting if you decide to go this route.

Ultimately, the decision to use micro-services should be based on a thorough assessment of your business needs and available resources, rather than simply following a trend or industry hype.

Set up:

  • Used AWS ECS (ec2 launch type) with services and task definitions defined
  • 11 Micro-services, 11 containers are spinning
  • Cost: Rs.12k ($160) per month

Workaround:

  • Consider using AWS Fargate type but not sure these issues get resolved
  • Deploy all the services in one EC2 Instance without using ECS

Liferay 7.3: Add service builder to the portlet


In the past, I made the decision to create the portlet and service builder directly within the Eclipse workspace, rather than creating a Liferay workspace project within the Eclipse workspace. However, this approach has caused some challenges when attempting to add the service builder to my portlet, as both of them are located within the Eclipse workspace.

Could not run phased build action using Gradle distribution 'https://services.gradle.org/distributions/gradle-5.6.4-bin.zip'.
Build file '/home/abhilash/eclipse-workspace/register-emailbox/build.gradle' line: 32
A problem occurred evaluating root project 'register-emailbox'.
Project with path ':sitesService:sitesService-api' could not be found in root project 'register-emailbox'.

Several individuals have encountered this particular issue, and you can find detailed guidance on resolving it in the Liferay developer article focused on creating a service builder.

https://liferay.dev/blogs/-/blogs/creating-service-builder-mvc-portlet-in-liferay-7-with-liferay-ide-3-

People reactions:

But no solution mentioned here

Through extensive research, I discovered that the solution to this issue requires creating both a portlet and a service builder within the Liferay workspace, rather than the Eclipse workspace. Specifically, it is essential to create a Liferay workspace project inside the Eclipse workspace to address this problem effectively.

Lets do that this time.

Click File -> New -> Liferay Workspace Project

Provide a Project Name and click on Finish

Next right click on the da-workspace, New -> Liferay Module Project

Provide the Project Name, then it automatically changes the Location

Provide the class name and project name

Deploy this service by clicking on the gradle section of IDE and double click on deploy

Deployed successfully

You can see the module os created inside our new Liferay Workspace: da-workspace

Jar file created

Copy this jar file and paste into the liferay server folder path given below:

~/liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/deploy

You can see the server log like this:

2020-04-14 09:16:09.299 INFO  [fileinstall-/home/abhilash/liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/osgi/modules][BundleStartStopLogger:39] STARTED com.emailbox_1.0.0 [1117]

Status -> STARTED

Now delete our old services. Goto the Goshell and uninstal the bundles:

Now goto the liferay and check our newly created portlet

Now lets repeat the steps for creating the service-builder from the previous article. But this time create it from da-workspace

File -> New -> Liferay Module Project

Services are created – For details check the previous article

Folder structure for the portlet and the service builder

Add the details as shown in the below screenshots (If any doubt check the previous article).

Do builder service and deploy

Copy this jar files one by one to the server’s deploy folder. First *api.jar and then *service.jar

Server logs:

liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/osgi/modules][BundleStartStopLogger:39] STARTED com.siteservice.api_1.0.0 [1118]

liferay-ce-portal-7.3.0-ga1/osgi/modules][BundleStartStopLogger:39] STARTED com.siteservice.service_1.0.0 [1119]


Check the database, you can see the Site_ Table and columns are created.

Now add the service builder dependancy to the portlet

Add this two lines in the build.gradle file

Right click on showEmailBox portlet and gradle -> refresh gradle project

DONE! You are successfully binded the service builder to your portlet.

now add the following to your portal class file above the doView function

@Reference
private SiteLocalService _siteLocalService;

now you can use the following default functions provided by liferay on the service.

_siteLocalService.fetchSite(23);
_siteLocalService.createSite(2344);
_siteLocalService.deleteSite(2233);
_siteLocalService.getSitesCount();
_siteLocalService.updateSite(site);

But what is we needed to fetch suppose some sites which has particular site_id Or fetch all sites which has registered after this time etc?

For all these custom query to mysql db, we needed to create a custom finder methods. So lets create one.

Open service.xml of `siteService-service`

Click on Finders and add Name and Type

Click on Finder column and add the db column to find

Click on Source, you can see the finder is added

Double click on the buildService to build the service

Now we can add custom finder findBySiteId to this service.

Open siteLocalServiceImpl.java

package com.siteservice.service.impl;

import com.liferay.portal.aop.AopService;
import com.siteservice.model.Site;
import com.siteservice.service.base.SiteLocalServiceBaseImpl;

import java.util.List;

import org.osgi.service.component.annotations.Component;


@Component(
	property = "model.class.name=com.siteservice.model.Site",
	service = AopService.class
)
public class SiteLocalServiceImpl extends SiteLocalServiceBaseImpl {

	public List<Site> findBySiteId(long site_id) {
		return sitePersistence.findBySiteId(site_id);
	}
}

Now do the buildService for siteService. Then Gradle -> Refresh and deploy the service. Copy this jar files one by one to the server’s deploy folder. First *api.jar and then *service.jar

Refresh Gradle project for the portlet – showEmailBox

Add the following to the doView function of the portlet

Site site = _siteLocalService.findBySiteId(2233).get(0);
		
System.out.println("We got the site: ---------");
System.out.println(site);

and don’t forget to create a site entry in the database with id: 2233

mysql> insert into Site_ (id_, site_id, name, register_from_date, register_to_date, created_at, updated_at) values (1, 2233, 'Site 2020', '2020-01-01', '2020-06-19', CURDATE(), CURDATE());

deploy the portlet and check you are getting the site in the server console.

that’s it for now, will see in the next article.

Liferay 7.3: Create custom database services (service-builder)

STEP 1:

Open the IDE. Goto File -> New -> Liferay Module Project


Select `service-builder` as Template

Click Next. Provide the package name and click finish

After that you can see two folders are created (*-api and *-service) inside your workspace.

And three folders in the IDE

Open siteService-service and click on service.xml . Click on the Entities and delete the default Foo column

And then add the Entity named Site . It is just an Entity, that connects to the table.

Click on the Site Entity and provide the table name

Add the Table Name

Add the columns as many as you want.

Select the column type from here:

Click on the Source Tab and you can see in the service.xml details of all columns that added.

Double click on the buildService to build the new service and double click on the deploy to deploy the service.

Now click on the down arrow and gradle -> refresh project. You can see the bundles created.

And the .jar bundles inside the osgi modules

Copy this *-api.jar file into the deploy folder of the server.

~/liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/deploy

and then copy the *-service.jar into the same folder

You can see these are processing and started in the server logs.

INFO  [com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][AutoDeployDir:263] Processing sitesService.api.jar

~/liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/osgi/modules][BundleStartStopLogger:39] STARTED sitesService.api_1.0.0 [1115]

[com.liferay.portal.kernel.deploy.auto.AutoDeployScanner][AutoDeployDir:263] Processing sitesService.service.jar

~/liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/osgi/modules][BundleStartStopLogger:39] STARTED sitesService.service_1.0.0 [1116]


Now check the database, if the Site_ table with all columns are created or not

You can see the table and columns are created. In the next topic we discuss about adding services to this service builder.

Liferay 7.3: Create a custom MVC portlet

What is a portlet?

A portlet is fragment on a webpage as web application and is used with portlets on the same webpage.

When you access a web site, you interact with an application. That application may be simple: it may only show you information, such as an article. The application may be complex, including forms, sending data etc. These applications run on a platform that provides application developers the building blocks they need to make applications.

If there are so many implementations of MVC frameworks in Java, why did Liferay create yet another one?

Liferay MVC provides these benefits:

It’s lightweight, as opposed to many other Java MVC frameworks.
There are no special configuration files that need to be kept in sync with your code.
It’s a simple extension of GenericPortlet.
You avoid writing a bunch of boilerplate code, since Liferay’s MVC framework simply looks for some pre-defined parameters when the init() method is called.
The controller can be broken down into MVC command classes, each of which handles the controller code for a particular portlet phase (render, action, and resource serving phases).
Liferay’s portlets use it. That means there are plenty of robust implementations to reference when you need to design or troubleshoot your Liferay applications.

Each portlet phase executes different operations:

Init: 

The init()  method is called by the portlet container during deployment and reads init parameters defined in portlet.xml file. The Portlet interface exposes the init method as:  void init (PortletConfig config) throws PortletException
The PortletConfig interface is  to retrieve configuration  from the portlet definition in the deployment descriptor. The portlet can only read the configuration data. The configuration information contains the portlet name, the portlet initialization parameters, the portlet resource bundle and the portlet application context.

Render:

Generates the portlet’s contents based on the portlet’s current state. When this phase runs on one portlet, it also runs on all other portlets on the page. The Render phase runs when any portlets on the page complete the Action or Event phases.

In this phase portlet generates content and renders on webpage.

The render phase is called in below cases:
1. The page that contains portlet is rendered on web page
2. After completing Action Phase
3. After completing Event Processing phase

below is example:

<portlet:renderURL var=“loadEmployees”> <portlet:param name=”mvcPath”
value=”/WEB-INF/view/empList.jsp” /> </portlet:renderURL>
<a href=”<%=loadEmployees%>”>Click here</a>


Action:

In response to a user action, performs some operation that changes the portlet’s state. The Action phase can also trigger events that are processed by the Event phase. Following the Action phase and optional Event phase, the Render phase then regenerates the portlet’s contents.

 its result of user actions such as add,edit, delete

  1. only one portlet can be entered into action phase for a request in a portlet container
  2. Any events triggered during the Action phase are handled during the Event phaseof the portlet lifecycle. Events can be used when portlets want to communicatewith each other. The Render phase will be called when all events have been handled.


Event:

Processes events triggered in the Action phase. Events are used for IPC. Once the portlet processes all events, the portal calls the Render phase on all portlets on the page.
Resource-serving: Serves a resource independent from the rest of the lifecycle. This lets a portlet serve dynamic content without running the Render phase on all portlets on a page. The Resource-serving phase handles AJAX requests.

Reference:

You can see more details and clarify your doubts by checking the following docs:

https://help.liferay.com/hc/en-us/articles/360018159451-Liferay-MVC-Portlet-

https://help.liferay.com/hc/en-us/articles/360018159431-Introduction-to-Portlets-

https://help.liferay.com/hc/en-us/articles/360017880432-Creating-an-MVC-Portlet-

http://www.javasavvy.com/liferay-portlet-basics-and-lifecycle/

Now we get into the action.

Step 1: Open Developer Studio and goto File -> New -> Liferay Module Project

Add Project Name, select mvc-portlet

Add class Name and package name and click finish

Step 2: Take Gradle task from right side section and double click on the deploy of created portlet

You can check the created portlet in the Studio’s workspace folder as above

The controller class of the portlet

Step 3: We will be changing the Class file and view file and deploy the changes and check

Add some code snnippet inside the above java Class, so that class look like this:

package com.register.portlet;

import com.register.constants.CheckRegisterPortletKeys;

import java.io.IOException;

import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet;

import javax.portlet.Portlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.osgi.service.component.annotations.Component;

/**
 * @author abhilash
 */
@Component(
	immediate = true,
	property = {
		"com.liferay.portlet.display-category=Register",
		"com.liferay.portlet.header-portlet-css=/css/main.css",
		"com.liferay.portlet.instanceable=true",
		"javax.portlet.display-name=CheckRegister",
		"javax.portlet.init-param.template-path=/",
		"javax.portlet.init-param.view-template=/view.jsp",
		"javax.portlet.name=" + CheckRegisterPortletKeys.CHECKREGISTER,
		"javax.portlet.resource-bundle=content.Language",
		"javax.portlet.security-role-ref=power-user,user"
	},
	service = Portlet.class
)
public class CheckRegisterPortlet extends MVCPortlet {
	public void doView(RenderRequest renderRequest, RenderResponse renderResponse) 
		   throws IOException, PortletException {
		System.out.println("inside my check registration logic controller");
		super.doView(renderRequest, renderResponse);
	}
}

Change the view.jsp as above

Step 4: Deploy again so that you can see the jar file is created as below:

The jar file created

Copy the jar file into this tomcat server folder, so that it can pick the package

Step 5: You can see the package status in the Gogo shell Liferay provides, goto the http://localhost:8080 and check inside the Configuration section Gogo Shell. Type command: lb

See the status – Installed. It should be ACTIVE after we deploy it.

Here are the list of osgi lifecycle status:

Step 6: Handle the Errors if any

I am getting some issues with this creation, lets see what is the problem.

I don’t have any idea why I am getting this. After some research I tried to add the module that is missing here, but no luck. Then I realised we are on Liferay 7.3 and See the pic of the IDE there we selected 7.2 version because thats the latest version available there. Hmm…So…yeahh that may be the issue here. You got that!

So Update your IDE and create the package again.

Now it Works!

And check our newly created portlet in the right side section (inside Widget) of Liferay Site.

You can see this messge that we wrote inside the Class inside my check registration logic controller in your server console in IDE. And this message This portlet is created by Abhilash inside the Portlet.

Congrats .. You have created your first custom portlet in Liferay.

Liferay 7.3: Developing custom themes

You can see the details for setting up themes from here:

https://help.liferay.com/hc/en-us/articles/360034979312-Setting-up-the-Theme

Goto your workspace folder (our developer studio workspace ~/eclipse-workspace):

$ cd ~/eclipse-workspace
$ nvm use 10.5
$ npm install -g generator-liferay-theme
$ npm install -g yo gulp
$ yo liferay-theme


Provide theme name, id, liferay version and font information

? What would you like to call your theme? Theme Moon
? What id would you like to give to your theme? theme-moon
? Which version of Liferay is this theme for? 7.3
? Would you like to add Font Awesome to your theme? No
.........
The project has been created successfully.

 Now we will invoke gulp init for you, to configure your deployment
strategy. 

Remember, that you can change your answers whenever you want by 
running gulp init again.

? Select your deployment strategy (Use arrow keys)
❯ Local App Server   // select this
  Docker Container 
  Other 

? Select your deployment strategy Local App Server
? Enter the path to your app server directory: /home/abhilash/liferay-ce-portal-tomcat-7.3.0-ga1-20200127150653953/liferay-ce-portal-7.3.0-ga1/tomcat-9.0.17
? Enter the url to your production or development site: http://localhost:8080


Run the command below from the theme’s root folder to build the files:

$ cd theme-moon
$ gulp build   # this creates the build folder

Now do the following changes to edit the created theme.

** Create a new /src/templates/ folder and copy portal_normal.ftl from the build/templates/ folder into it.

Configure the theme to extend the Atlas theme. Add a clay.scss file to the theme’s /src/css/ folder and add the import shown below:

@import "clay/atlas";

Create an _imports.scss file in the /src/css/ folder and add the imports shown below to it. This includes the default imports and replaces the clay/base-variables with the Atlas base variables:

@import "bourbon";

@import "mixins";

@import "compat/mixins";

@import "clay/atlas-variables";

You’ve generated the theme, prepared it for development, and configured it to extend the Atlas theme

Customizing the Header and Logo of your theme

Open portal_normal.ftl and replace the <header>...</header> element and contents with the updated code snippet below. This updates the structure slightly, making the banner expand the full width of the Header, and adds a new header_css_class variable to the class attribute. This variable is defined in a later step.

<header class="${header_css_class}">
	<div class="container-fluid" id="banner" role="banner">
		<a class="${logo_css_class}" href="${site_default_url}" title="<@liferay.language_format arguments="${site_name}" key="go-to-x" />">
			<img alt="${logo_description}" height="${site_logo_height}" src="${site_logo}" width="${site_logo_width}" />
			<#if show_site_name>
				${site_name}
			</#if>
		</a>

		<#if has_navigation>
			<#include "${full_templates_path}/navigation.ftl" />
		</#if>
	</div>
</header>

Replace the <div class="container-fluid" id="wrapper"> element with the updated code below to remove some margins and padding:

<div class="container-fluid mt-0 pt-0 px-0" id="wrapper">

And move the wrapper down, and place it directly above the <section id="content"> element:

<div class="container-fluid mt-0 pt-0 px-0" id="wrapper">
  <section id="content">
  ...
  </section>
  <footer...>
  ...
  </footer>
</div>

The logo’s height is retrieved with the ${site_logo_height} variable. The height of the logo is a bit too large for the this theme, so you must adjust it. Remove the width attribute from the logo’s image so it defaults to auto:

<img alt="${logo_description}" height="${site_logo_height}" src="${site_logo}" />

Create init_custom.ftl in your theme’s /src/templates/ folder and assign the logo’s site_logo_height variable to the value below:

<#assign site_logo_height = 56 />

Assign the new header_css_class variable you added in step one to the value below:

<
#assign header_css_class = 
"navbar navbar-expand-md navbar-dark flex-column flex-md-row bd-navbar" 
/>

This applies Bootstrap and Clay utility classes to provide the overall look and feel of the Header. Assigning the classes to a variable keeps portal_normal clean and makes the code easy to maintain. If you want to update the classes, you just have to modify the variable (e.g. header_css_class = header_css_class + " my-new-class").

Add the code snippet below to update the logo_css_class variable to use Bootstrap’s navbar-brand class:

NEW THUMBNAIL FOR THE THEME

Before you upload the theme to see what it looks like so far, you must create a theme thumbnail so you can identify it. Create a  thumbnail.png and replace the default from the /src/images/ folder. Note that its dimensions are 480px by 270px. These dimensions are required to display the theme thumbnail properly.

DEVELOPER MODE (If not enabled you may face CSS / JS loading issues )

The theme isn’t complete yet, but you’ll deploy what you have so you can replace the default logo with the your logo. Enable Developer Mode before deploying your theme, so the theme’s files are not cached for future deployments.

Once I faced CSS loading issue in my AWS Liferay site for one theme. After a lot of research I found that, the server doesn’t have portal-ext.properties file and not enabled the so called Developer Mode

Custom CSS Loading in Liferay

My custom _import.scss almost look like this:

/* These inject tags are used for dynamically creating imports for themelet styles, you can place them where ever you like in this file. */

/* inject:imports */

/* endinject */

/* This file allows you to override default styles in one central location for easier upgrade and maintenance. */

@import "bourbon";

@import "mixins";

@import "compat/mixins";

@import "clay/atlas-variables";

@import "./style.scss";

@import "./innerstyle.scss";

@import "./mixedslider.scss";

------

Liferay loads this css file in HTML like as follows:

<link class="lfr-css-file" data-senna-track="temporary" href="http://localhost:8080/o/myTheme-theme/css/main.css?browserId=other&themeId=myTheme_WAR_myThemetheme&languageId=en_US&b=7301&t=1588754322000" id="liferayThemeCSS" rel="stylesheet" type="text/css" />

When clicking on this file, I get different css as follows instead of the _import.scss file listed above.

/*1559583096000*/
.loadingmask-message{background:transparent;border-width:0;display:block;height:1em;margin-left:auto;margin-right:auto;position:relative;text-align:left;width:1em}.loadingmask-message .loadingmask-message-content{-webkit-animation:loading-animation 1.2s infinite ease-out;animation:loading-animation 1.2s 
........

This is because of I was not enabled the ‘Developer Mode’ in portal.ext file.

After enabling it as below, my _import.scss styles shows up in Liferay’s main.css file.

Create a portal-ext.properties file in your server’s root folder if it doesn’t exist.

Add the line below to it:

include-and-override=portal-developer.properties

Start the server, if it’s not already started, and deploy the theme with the command below:

$ gulp deploy
.....
[20:34:49] Finished 'plugin:deploy' after 32 ms
[20:34:49] Finished 'deploy:war' after 32 ms
[20:34:49] Finished 'deploy' after 4.78 s

CHANGE LOGO

Open the Control Menu and navigate to Site Builder → Pages. Click the Gear icon next to Public Pages to open the configuration menu. Under the Look and Feel tab, scroll down and click the Change Current Theme button and select the Lunar Resort Theme. Scroll to the Logo heading, click the Change button, upload the new-logo.png logo, and click the Save button to apply the theme and logo.

Reference: https://help.liferay.com/hc/en-us/articles/360034979332-Customizing-the-Lunar-Resort-s-Header-and-Logo

IMPORT THIS THEME IN IDE

And at last how to import this theme so that your tomcat server runs it?

Goto your Developer studio
Goto File -> Import -> Import gradle project -> select the path of this theme root directory -> Done!

Click on the File -> Import

Select the created theme path

Right click on the server and restart it. OR right click on the theme after draging it to the server and click on restart

Then goto http://localhost:8080/

click on Settings icon on top -> Under theme select

Define a specific look and feel for this page.

New theme added

Click on the new theme and click SAVE button. You can see your new theme activated. Congrats!

How to reinstall mongodb in ubuntu linux

Before reinstalling mongodb, in your linux system check whats installed in the system

 $ sudo dpkg -l | grep mongo
 ii  mongodb-org                              2.6.3                                       amd64        MongoDB open source document-oriented database system (metapackage)
 ii  mongodb-org-mongos                       2.6.3                                       amd64        MongoDB sharded cluster query router
 ii  mongodb-org-server                       2.6.3                                       amd64        MongoDB database server
 ii  mongodb-org-shell                        2.6.3                                       amd64        MongoDB shell client
 ii  mongodb-org-tools                        2.6.3                                       amd64        MongoDB tools

Remove all
$ sudo apt-get remove mongodb*

Install mongodb again, check mongodb org

$ sudo apt-get install -y mongodb-org

For particular version

$ sudo apt-get install -y mongodb-org=2.6.5 mongodb-org-server=2.6.5 mongodb-org-shell=2.6.5 mongodb-org-mongos=2.6.5 mongodb-org-tools=2.6.5


check whats newly installed

$ sudo dpkg -l | grep mongo
 ii  mongodb-org                              2.6.8                                       amd64        MongoDB open source document-oriented database system (metapackage)
 ii  mongodb-org-mongos                       2.6.8                                       amd64        MongoDB sharded cluster query router
 ii  mongodb-org-server                       2.6.8                                       amd64        MongoDB database server
 ii  mongodb-org-shell                        2.6.8                                       amd64        MongoDB shell client
 ii  mongodb-org-tools                        2.6.8                                       amd64        MongoDB tools

check mongodb server status

$ sudo service mongod status

Start mongodb server

$ sudo service mongod start

Start mongo shell

$ mongo

check mongodb log file here

 $ tail -n 200 /var/log/mongodb/mongod.log