08 December, 2017

Create Servlet Project as Module

You would have seen that many times we are writing out own servlet in Liferay portal to achieve some specific use case.
In DXP, You can still cont. with such implementation and here you will see how you can write your servlet application as module.

Create liferay module type of API using developer studio or blade ci.

In bnd file:

 Bundle-Name: test-servlet
Bundle-SymbolicName: TestServlet
Bundle-Version: 1.0.0

Web-ContextPath: /test


In build.gradle:

 dependencies {
compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
}


In component class,

@Component(
immediate = true,
property = {
"osgi.http.whiteboard.context.path=/test",
"osgi.http.whiteboard.servlet.name=com.jignesh.MyServlet",
"osgi.http.whiteboard.servlet.pattern=/my-servlet",
},
service = Servlet.class)
public class MyServlet extends HttpServlet {
 @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doPost(req, resp);
}
}

Just deploy the module and acces through URL : http://localhost:8080/o/test/my-servlet

Liferay DXP clustering

Hello Friends,

I am sure you would be looking for simple steps for DXP clustering.

Note:Liferay 7 clustering you can visit https://community.liferay.com/news/new-clustering-code-for-liferay-portal-community/ 

Image result for server clustering liferay

Steps for Liferay DXP clustering :

Liferay Setup:

- Setup liferay DXP in 2 separate servers which can be accesses using separate IP
- Both servers should be accessible to each other
- Here we are not going to setup 2 DXP instances in single server as it's not good for architectural perspective for production. 
- Setup first instance and populate DB data with single instance
- when you setup another DXP instance then point the same DB which you used for first instance. We are not going to use separate read write DB server here and will use single DB for read and write for both the instances. For production setup, you can think to create separate DB server for read and write operation.

Liferay Configurations for clustering 

Portal-ext Configuration for Node-1 and Node-2

liferay.home=/u01/app/oracle/product/fmw1/user_projects/domains

jdbc.default.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.default.url=jdbc:oracle:thin:@//localhost:1540/xe
jdbc.default.username=username
jdbc.default.password=password
setup.wizard.enabled=false

# For clustering settings
dl.store.impl=com.liferay.portal.store.db.DBStore
cluster.link.enabled=true
cluster.link.channel.properties.control=/u01/app/oracle/product/fmw1/user_projects/domains/base_domain/tcp.xml
cluster.link.channel.properties.transport.0=/u01/app/oracle/product/fmw1/user_projects/domains/base_domain/tcp.xml
cluster.link.autodetect.address=
cluster.link.bind.addr["cluster-link-control"]=10.10.36.111
cluster.link.bind.addr["cluster-link-udp"]=10.10.36.111
ehcache.cluster.link.replication.enabled=true
lucene.replicate.write=true
cluster.executor.debug.enabled=true
cluster.link.channel.system.properties=jgroups.bind_addr:${cluster.link.bind.addr["cluster-link-udp"]},jgroups.bind_interface:eth0


In above property file, IP address would be your server IP address and TCP.xml we will see below.

TCP.xml configuration Node-1 and Node-2

- You can get this file from Liferay foundation.lpkg file
- extract lpkg and extract com.liferay.portal.cluster.multiple-1.0.11.jar where you can see tcp.xml
- copy tcp.xml file in local and update as per below settings which are highlighted. Here we are using TCPPING. You can use JDPCPing and other methods which liferay supports.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="urn:org:jgroups"
        xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd">
    <TCP bind_port="7800"
          singleton_name="liferay_jgroups_tcp"
         recv_buf_size="${tcp.recv_buf_size:5M}"
         send_buf_size="${tcp.send_buf_size:5M}"
         max_bundle_size="64K"
         max_bundle_timeout="30"
         use_send_queues="true"
         sock_conn_timeout="300"

         timer_type="new3"
         timer.min_threads="4"
         timer.max_threads="10"
         timer.keep_alive_time="3000"
         timer.queue_max_size="500"

         thread_pool.enabled="true"
         thread_pool.min_threads="2"
         thread_pool.max_threads="8"
         thread_pool.keep_alive_time="5000"
         thread_pool.queue_enabled="true"
         thread_pool.queue_max_size="10000"
         thread_pool.rejection_policy="discard"

         oob_thread_pool.enabled="true"
         oob_thread_pool.min_threads="1"
         oob_thread_pool.max_threads="8"
         oob_thread_pool.keep_alive_time="5000"
         oob_thread_pool.queue_enabled="false"
         oob_thread_pool.queue_max_size="100"
         oob_thread_pool.rejection_policy="discard"/>

 <TCPPING async_discovery="true"
             initial_hosts="${jgroups.tcpping.initial_hosts:10.10.36.111[7800],10.10.36.112[7800]}"
             port_range="2"/>
    <MERGE3  min_interval="10000"
             max_interval="30000"/>
    <FD_SOCK/>
    <FD timeout="3000" max_tries="3" />
    <VERIFY_SUSPECT timeout="1500"  />
    <BARRIER />
    <pbcast.NAKACK2 use_mcast_xmit="false"
                   discard_delivered_msgs="true"/>
    <UNICAST3 />
    <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
                   max_bytes="4M"/>
    <pbcast.GMS print_local_addr="true" join_timeout="2000"
                view_bundling="true"/>
    <MFC max_credits="2M"
         min_threshold="0.4"/>
    <FRAG2 frag_size="60K"  />
    <!--RSVP resend_interval="2000" timeout="10000"/-->
    <pbcast.STATE_TRANSFER/>
</config>

- Put this tcp.xml file in classpath of server and restart both the servers (nodes).

Setup shared Elastic server

You can refer https://customer.liferay.com/documentation/7.0/deploy/-/official_documentation/deployment/configuring-elasticsearch-for-liferay-0 for setting up elastic search server and point this server to both nodes so that both nodes keep common index records.

How to verify

- Look server log for both nodes where you will be able to see logs which tells you that both nodes listening each other.
- You can also create web content/Document in one node and check in another node. it should reflect without re-indexing and removing database cache.

References:
- Liferay DXP Clustering
- How to Install Liferay DXP in a Clustered Environment
- Managing Liferay DXP's Distributed Cache

07 December, 2017

Liferay DXP setup with Weblogic

Download latest DXP version

  1. For Enterprise Edition, we need to download Liferay DXP 
  2. For Community Edition, we need to download Liferay Portal

As we are using (EE ) Enterprise Edition, we will download Liferay DXP.

Note:Download latest DXP server from Liferay customer portal, using the credentials provided by Liferay as part of licensing agreement. Download Liferay DXP’s WAR file and dependencies from the Customer Portal
Go to Products>>Liferay DXP click on Downloads


You’ll need the following files:
· liferay-dxp-digital-enterprise-[version].war: Liferay DXP WAR file
· liferay-dxp-digital-enterprise-dependencies-[version].zip: Liferay DXP dependencies

· liferay-dxp-digital-enterprise-osgi-[version].zip: Liferay DXP OSGi dependencies

Configuring Web Logic’s Node Manager

WebLogic requires a Node Manager to start and stop managed servers. Before installing Liferay DXP, you must configure the Node Manager included with your WebLogic installation. You’ll do this via the domains/your_domain_name/nodemanager/nodemanager.properties file. Open this file, and set the SecureListener property to false:

we have below path for setup :
/u01/app1/oracle/product/fmw12C/user_projects/domains/base_domain/nodemanager

If you’re running WebLogic on Mac or Linux, you may also need to set the nativeVersionEnabled property to false.

Also note that with SecureListener set to true, you must configure your machine in the Admin Server’s console to accept unencrypted connections from the Node Manager. To do this, first log in to your Admin Server and select Environment → Machines from the Domain Structure box on the left. Click your machine in the table and then select the Configuration → Node Manager tab. In the Type field, select Plain from the selector menu, and then click Save. You must restart your Admin Server for this change to take effect. 



Configuring Weblogic

Next, you must set some variables in two WebLogic startup scripts. These variables and scripts are as follows. Be sure to use set instead of export if you’re on Windows. 
1. your-domain/startWebLogic.[cmd|sh]This is the Admin Server’s startup script.
2. your-domain/bin/startWebLogic.[cmd|sh]This is the startup script for Managed Servers. 
Sample path for above files would be :
/u01/app/oracle/product/fmw1/user_projects/domains/base_domain/bin

Add the following variables to both startWebLogic.[cmd|sh] scripts:
export DERBY_FLAG="false"
export JAVA_OPTIONS="${JAVA_OPTIONS} -Dfile.encoding=UTF-8 -da:org.apache.lucene... -da:org.aspectj..."
export MW_HOME="u01/app1/oracle/product/fmw12C/wlserver"
export USER_MEM_ARGS="-Xmx1024m -XX:MetaspaceSize=512m"

Also make sure to set MW_HOME to the directory containing your WebLogic server on your machine. For example: (leave it as is as $MW_HOME)
/home/oracle/Oracle_Home/wlserver
You must also ensure that the Node Manager sets Liferay DXP’s memory requirements when starting the Managed Server. In the Admin Server’s console UI, navigate to the Managed Server you want to deploy Liferay DXP to and select the Server Start tab. Enter the following into the Arguments field: 
-Xmx2048m -XX:MaxMetaspaceSize=512m
Click Save when you’re finished. 

Setting Liferay DXP Properties

Before installing Liferay DXP, you must need to set the Liferay Home folder’s location via the liferay.home property in a portal-ext.properties file. You can also use this file to override other Liferay DXP properties that you may need. 

1. First, decide which directory you want to serve as Liferay Home. In WebLogic, your domain’s folder is generally Liferay Home, but you can choose any folder on your machine. Then create your portal-ext.properties file and add the liferay.home property: 

 liferay.home=/u01/app/oracle/product/fmw1/user_projects/domains

Also keep one version of Portal-ext.properties file will be save in above path which will be useful to override properties in future and make sure just keep liferay.home in portal-ext.properties .This can be override anytime once liferay home path set in portal-ext which we will keep in war file of liferay DXP.

How to put portal-ext.properties in DXP war file

Now, we have to extract War file (for e.g liferay-dxp-digital-enterprise-7.0-sp6-20171010144253003.war) and in that WEB-INF/classes folder we have to place portal-ext.properties and re-war it again.

Take backup of that DXP war file at same path and rename it as backup
Copy the original war file to tmp folder and follow below steps to extract from war and re-war.

cp warfile.war /tmp
cd /tmp
unzip warfile.war
cd WEB-INF
cd classes

Go to the path where your portal-ext.properties file is saved , Go to domain path: /u01/app/oracle/product/fmw1/user_projects/domains
cp portal-ext.properties  /u01/app/oracle/product/fmw1/user_projects/domains/base_domain/tmp/WEB-INF/classes

cd ...
cd ..
zip -r -u warfile.war WEB-INF
zip –r –u warfile.war dtd
zip –r –u warfile.war errors
zip –r –u warfile.war html
zip –r –u warfile.war index.jsp
zip –r –u warfile.war layouttpl

By this way again in tmp folder that war file will be ready. Copy that war file outside that temp folder at below path:
/u01/app/oracle/product/fmw1/user_projects/domains/base_domain

Now in future if you want to modify portal-ext, then you don't need to touch properties which we kept inside war file. you can just go to liferay home path which you set earlier and can override portal-ext.properties.

Installing Liferay DXP dependencies

1. unzip zip file (liferay-dxp-digital-enterprise-dependencies-)at below folder and place 7 files including ojdbc.jar file

/u01/app/oracle/product/fmw12C/user_projects/domains/base_domain/lib

2.liferay-dxp-digital-enterprise-osgi-[version].zipUnzip this file and place its contents in the Liferay_Home/osgi folder (/u01/app/oracle/product/fmw12C/user_projects/domains/osgi) If file not there so please create it

3. Copy ojdbc .jar file in /u01/app/oracle/product/fmw12C/user_projects/domains/base_domain/lib folder

Security Configuration

You must have to enable Java Security on your WebLogic server and specify a security policy to grant Liferay DXP access to your server. 
First, you’ll grant Liferay DXP access to your server. This configuration opens all permissions–you can fine-tune your policy’s permissions later. If it doesn’t already exist, create a policy file named weblogic.policy in your $WL_HOME/server/lib folder. 
/u01/app/oracle/product/fmw/ wlserver_10.3 /server/lib
Replace its contents with the following: 
grant {
    permission java.security.AllPermission;
};

To enable security on your WebLogic server and direct the server to your policy file, 
open the setDomainEnv.[cmd|sh] file in your domain’s bin folder. 
Then set the -Djava.security.manager Java option and set the property 
-Djava.security.policy to your weblogic.policy file. You can specify both settings on the same line like this:
Path to go is = /u01/app/oracle/product/fmw1/user_projects/domains/base_domain/bin
-Djava.security.manager -Djava.security.policy==$WL_HOME/server/lib/weblogic.policy

The double equals sign tells the app server to use only this policy file. Any other security policies are ignored.

In Weblogic console >> <Your-Managed-Server> , Go to Server_stat tab and add “-Xmx2048m -XX:MaxMetaspaceSize=512m” in Arguments box

Deploying Liferay DXP

Note:Before you start DXP deployment, just restart weblogic server so that dependencies which you kept in weblogic classpath will get loaded.

As mentioned earlier, although you can deploy Liferay DXP to a WebLogic Admin Server, you should instead deploy it to a WebLogic Managed Server. Dedicating the Admin Server to managing other servers that run your apps is a best practice. 
Follow these steps to deploy Liferay DXP to a Managed Server: 

1. Make sure the Managed Server you want to deploy Liferay DXP to, is shut down.



2.In your Admin Server’s console UI, select Deployments from the Domain Structure box on the left hand side. Then click Install to start a new deployment. 


3.Select the Liferay DXP WAR file or its expanded contents on your file system. It will take your domain patch already. Alternatively, you can upload the WAR file by clicking the Upload your file(s) link. Click Next


4.Select Install this deployment as an application and click Next.



5.Select the Managed Server you want to deploy Liferay DXP to, and click Next



6.If the default name is appropriate for your installation, keep it. Otherwise, give it a name of your choosing and click Next

7.Click Finish. After the deployment finishes, click Save if you want to save the configuration. 
8.Start the Managed Server you deployed Liferay DXP to. Liferay DXP precompiles all the JSPs, and then launches. 

Note:
When you will start managed server and if you you will get error for boot.properties, so again enter below details in booth.properties.
Username=weblogic username
Password:weblogicpassword
For changing details in boot.properties, path is: 
/u01/app/oracle/product/fmw1/user_projects/domains/base_domain/servers/<your-server-name>/security 
Once it will show server is up. Liferay should also up. You can check from the below url that Lifray is also running

04 December, 2017

Login Authentication Solutions

Hello Friends,

This article will be helpful to you when you choose to customize login with various Liferay DXP supported authentication mechanism.
And this is almost common requirement for each implementations so I will provide all possible ways to customize login functionality based on my knowledge and provide solution.

1) Liferay OOB Login Customization
  • Custom Module implementation
2) Custom Authentication
  • Auto Login Basic Auth Header
  • Auto Login Request Header
  • Token Based SSO
  • Auto Login Request Parameter
3) SSO Login by Liferay supported SSO provider
  • Liferay + OpenSSO
  • Liferay + CAS
  • Liferay + NTLM
  • Liferay + LDAP
  • Liferay + OpenId
  • Liferay + Facebook (Facebook Connect)
  • Liferay + Google  (Google Authorization)
4) SAML Based SSO Login


19 July, 2017

REST Client OSGi Bundle

Hello Friends,

If you are planing to create HTTP REST client using OSGi, Just follow the steps.

1) Create bundle project of type API using IDE
2) Write one Class called RestClient.java
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
//import org.apache.commons.logging.LogFactory;

/**
 * This example demonstrates how to create HTTP client for secure connection
 * context.
 */
/**
 * @author jignesh.vachhani
 *
 */
public class CustomHTTPClient {
private static final String username = "test";
private static final String password = "test";
private static final String host = "my.host.name";
private static final int port = 443;
private static final String protocol = "https";
static CloseableHttpClient httpclient = null;
static HttpHost targetHost = new HttpHost(host, port, protocol);

static HttpClientContext context = HttpClientContext.create();

public CustomHTTPClient() {
// Setting Credentials
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(host, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.BASIC),
new UsernamePasswordCredentials(username, password));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);

// Add AuthCache to the execution context
context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);

httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
}

static {
new CustomHTTPClient();
}

public final static void main(String[] args) throws Exception {
try {

boolean post = true;
boolean get = true;
if (post) {
HttpPost httpPost = new HttpPost(
"https://my.host.name/iam/governance/selfservice/api/v1/unauthservice/forgotusername");
String json = "{\r\n  \"email\": \"jigs.vachhani@gmail.com\"\r\n}";
StringEntity entity = new StringEntity(json);
httpPost.setEntity(entity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");

CloseableHttpResponse response = httpclient.execute(httpPost);
try {
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
EntityUtils.consume(entity);

} finally {
response.close();
}
}
if (get) {
HttpGet httpget = new HttpGet(
"https://my.host.name/iam/governance/selfservice/api/v1/users");
CloseableHttpResponse response = httpclient.execute(targetHost, httpget, context);
try {
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
System.out.println(EntityUtils.toString(response.getEntity()));
EntityUtils.consume(entity);

} finally {
response.close();
}
}
} finally {
httpclient.close();
}
}

}

3) define below dependencies in build.gradle
dependencies {
    compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "2.0.0"
    compileOnly group: "com.liferay.portal", name: "com.liferay.util.taglib", version: "2.0.0"
    compileOnly group: "javax.portlet", name: "portlet-api", version: "2.0"
    compileOnly group: "javax.servlet", name: "javax.servlet-api", version: "3.0.1"
    compileOnly group: "jstl", name: "jstl", version: "1.2"
    compileOnly group: "org.osgi", name: "osgi.cmpn", version: "6.0.0"
    compile group: 'commons-codec', name: 'commons-codec', version: '1.9'
    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5'
    compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4.1'

}
4) In bnd.bnd
Bundle-Name: sample-rest-client
Bundle-SymbolicName: sample.rest.client
Bundle-Version: 1.0.0
Export-Package: \
    sample.rest.client.constants,\
    sample.rest.client.api
 Include-Resource:\
@httpclient-4.5.jar,\
@httpcore-4.4.1.jar,\
@commons-codec-1.9.jar 



Note : Below dependencies required in class path :
httpclient-4.5.jar,\
httpcore-4.4.1.jar,\
commons-codec-1.9.jar 


Just compile or deploy and you are done. Its simple  interesting isn't it ?