Monday, December 19, 2016

Get Liferay Server folder path in liferay

To get the exact path of your server folder in Liferay , then the below code will be help you inspite of any Operating System.

import java.util.Properties;

Properties properties = PortalUtil.getPortalProperties();
String serverHome = properties.getProperty("liferay.home");

Thursday, December 15, 2016

Custom entity Indexer in Liferay

Planning to create the Indexer for your custom entity then here is an solution for that.

To search the custom table content through the search portlet of  Liferay, then we will create the Indexer(which is used for search).

Step 1 : Create your custom entity in service.xml

<entity name="myDB" local-service="true" remote-service="false" cache-enabled="true" >
<column name="manageentryID" type="long" primary="true" />
<column name="groupId" type="long" />
<column name="companyId" type="long" />
<column name="userId" type="long" />
<column name="lastModifiedDate" type="Date" />
<column name="myID" type="String" />
<column name="myName" type="String" />

<finder name="myID" return-type="myDB">
        <finder-column name="indexIsin" />
    </finder>
</entity>


Step 2 :- Create Indexer class in your portlet which will extends the BaseIndexer

ex:-

import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.search.BaseIndexer;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.DocumentImpl;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.search.SearchEngineUtil;
import com.liferay.portal.kernel.search.Summary;
import com.liferay.portal.kernel.util.GetterUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.portlet.PortletURL;

import org.apache.log4j.Logger;

public class Indexer extends BaseIndexer{

private static final Logger log = Logger.getLogger(Indexer.class);
public static final String[] CLASS_NAMES = { MyDB.class.getName() };
public static final String PORTLET_ID = "myportlet_WAR_myportlet";
public static int COUNT = getCount();

public static int getCount() {
int count = 1;
try {
count = MyDBLocalServiceUtil.getMyDBsCount();
} catch (SystemException e) {
e.printStackTrace();
}
return count;
}

@Override
public String[] getClassNames() {
// TODO Auto-generated method stub
return CLASS_NAMES;
}

@Override
public String getPortletId() {
// TODO Auto-generated method stub
return PORTLET_ID;
}

@Override
protected void doDelete(Object obj) throws Exception {
// TODO Auto-generated method stub

}

protected Document getDocumentUpdate(Object obj) throws Exception {

MyDB myDB = (MyDB) obj;
long groupId = getParentGroupId(myDB.getGroupId());
long scopeGroupId = myDB.getGroupId();
long companyId = myDB.getCompanyId();
String myID = myDB.getmyID();
String title = myDB.getmyName();

Document document = getBaseModelDocument(PORTLET_ID, MyDB);
document.addKeyword(Field.COMPANY_ID, companyId);
document.addKeyword(Field.GROUP_ID, groupId);
document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);

document.addKeyword("myID", myID);
document.addText(Field.TITLE, title);
return document;
}

@Override
protected Document doGetDocument(Object obj) throws Exception {
// TODO Auto-generated method stub
MyDB myDB = (MyDB) obj;
log.info("-----------  Adding the Document ------------");
long groupId = myDB.getGroupId();
long scopeGroupId = myDB.getGroupId();
long companyId = myDB.getCompanyId();
long userId = myDB.getUserId();
long manageentryID = myDB.getManageentryID();
Date modifiedDate = myDB.getLastModifiedDate();
String myID = myDB.getmyID();
String title = myDB.getmyName();
log.info("----------- Document ------------" + myDB.getManageentryID());
Document document = new DocumentImpl();//Way 2 usefull for both common jar or jar in same war
//Document document = getBaseModelDocument(PORTLET_ID, MyDB);//Way 1 It throws an error if your service jar is not available in same war
document.addUID(PORTLET_ID, manageentryID);// Mandatory for Way 2
document.addModifiedDate(modifiedDate);
document.addKeyword(Field.COMPANY_ID, companyId);//Mandatory for Way 1 or 2
document.addKeyword(Field.PORTLET_ID, PORTLET_ID);// Mandatory for Way 2
document.addKeyword(Field.GROUP_ID, groupId);//Mandatory for Way 1 or 2
document.addKeyword(Field.SCOPE_GROUP_ID, scopeGroupId);//Mandatory for Way 1 or 2
document.addKeyword(Field.USER_ID, userId); // Mandatory for Way 2
document.addKeyword(Field.ENTRY_CLASS_NAME, MyDB.class.getName());// Mandatory for Way 2
document.addKeyword(Field.ENTRY_CLASS_PK, manageentryID);// Mandatory for Way 2
document.addText(Field.TITLE, title); //Mandatory for Way 1 or 2
document.addKeyword("myID", myID);
document.addText(Field.TITLE, title); //Mandatory for Way 1 or 2
log.info("----------- myID IN DOCUMENT ------------" + document.get("myID"));
return document;
}

@Override
protected Summary doGetSummary(Document document, Locale locale,
String snippet, PortletURL portletURL) throws Exception {
String myID = document.get("myID");
MyDB myDB = null;
List totalRecord = new ArrayList();
if (myID.length() > 0) {
myDB = MyDBLocalServiceUtil.fetchBymyID(myID);
}
String title = document.get(Field.TITLE);
String content = snippet;
List indexList = null;

indexList = MyDBLocalServiceUtil.getMyDBs(0, -1);
for (MyDB tr : indexList) {
totalRecord.add(tr);
}
int pos = totalRecord.indexOf(myDB) + 1;
if (pos > 0) {
int page = pos / 10;
if (pos % 10 > 0) {
page = page + 1;
}
if (page == 0) {
page = 1;
}
portletURL.setParameter("cur", String.valueOf(page));
}
return new Summary(title, content, portletURL);
}


@Override
protected void doReindex(Object obj) throws Exception {
// TODO Auto-generated method stub
MyDB myDB = (MyDB) obj;
String searchEngineId = SearchEngineUtil.getDefaultSearchEngineId();
Document document = null;
try {
document = getDocument(MyDB);
SearchEngineUtil.updateDocument(searchEngineId,myDB.getCompanyId(), document);
} catch (Exception e) {
log.error("error while add document", e);
}
}

protected void doReindexUpdate(Object obj) throws Exception {
MyDB myDB = (MyDB) obj;
String searchEngineId = SearchEngineUtil.getDefaultSearchEngineId();
SearchEngineUtil.updateDocument(searchEngineId, myDB.getCompanyId(),
getDocumentUpdate(MyDB));
}

@Override
protected void doReindex(String className, long classPK) throws Exception {
// TODO Auto-generated method stub
MyDB myDB = MyDBLocalServiceUtil.getMyDB(classPK);
doReindex(MyDB);

}

@Override
protected void doReindex(String[] ids) throws Exception {
// TODO Auto-generated method stub
long companyId = GetterUtil.getLong(ids[0]);
doReindexAll(companyId);
}

private void doReindexAll(long companyId) throws Exception {
int count = MyDBLocalServiceUtil.getMyDBsCount();
int pages = count / Indexer.DEFAULT_INTERVAL;
for (int i = 0; i <= pages; i++) {
int start = (i * Indexer.DEFAULT_INTERVAL);
int end = start + Indexer.DEFAULT_INTERVAL;
reindexMyDB(companyId, start, end);
}
}

protected void reindexMyDB(long companyId, int start, int end)
throws Exception {
List myDBlist = MyDBLocalServiceUtil.getMyDBs(-1, -1);
if (myDBlist.isEmpty()) {
return;
}
Collection documents = new ArrayList();
COUNT = 1;
for (MyDB myDB : IndexDBlist) {
Document document = getDocument(myDB);
document.addText("count", String.valueOf(COUNT++));
documents.add(document);
}
String searchEngineId = SearchEngineUtil.getDefaultSearchEngineId();
SearchEngineUtil.updateDocuments(searchEngineId, companyId, documents);
}
@Override
protected String getPortletId(SearchContext searchContext) {
// TODO Auto-generated method stub
return PORTLET_ID;
}

}


Step 3 :- make an Indexer entry in your liferay-portlet.xml

<icon>/icon.png</icon>
<indexer-class>com.mypackage.Indexer</indexer-class>


Step 4 : call the Indexer while updating or inserting data into the data base myDB

public void createEntry(ThemeDisplay themeDisplay){
MyDB createdMyDBObject;
MyDB myDB = MyDBLocalServiceUtil.createMyDB("1234");
myDB.setGroupId(themeDisplay.getLayout().getGroupId());
myDB.setCompanyId(themeDisplay.getCompanyId());
myDB.setmyID("I786");
myDB.setUserId(themeDisplay.getUserId());
myDB.setmyName("I786");
try {
createdMyDBObject = MyDBLocalServiceUtil.updateMyDBFromCSV(myDB);
Indexer indexer = IndexerRegistryUtil.getIndexer(MyDB.class);
if(Validator.isNotNull(createdIndexDBObject))
indexer.reindex(createdIndexDBObject);
} catch (SystemException | SearchException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}




Thursday, November 24, 2016

Planning of Migrating from Liferay 6.x to Liferay DXP.


Liferay Digital Experience Platform (DXP) gives you a full view of the customer in order to create and manage consistent customer experiences across mobile, social, desktop, in store and other touch based devices. DXP prepares you to adapt quickly to future digital innovations.

Liferay DXP adopted new architecture with latest features in the web technologies. Due to architectural changes there will be many challenges while upgrade/migrate to latest Liferay DXP from Liferay 6.x.

Top 5 things to think before doing migration to Liferay DXP.

Backup existing data:-
“Backup of existing data is must before doing any migration”.
Migrating from Liferay 6.x to Liferay DXP, the first thing is to take proper backup from the current running server. The backup will help you revert back to older state, if anything doesn’t work properly.
Backup need to be taken for the below listed items.
·         Database schema
·         Files from data folder (which contain document and media files)
·         Custom configurations in the properties files. (portal-ext.properties)
·         PortalPreferences which are associated with portlets.

Note: In Liferay DXP PortalPreferences_ has been removed and replaced by a modular OSGi-based configuration framework.

Database upgrade:-
Once the database backup is done, we need to upgrade the database with respect to Liferay DXP.
Database comes first everywhere which you must require to migrate to make it compatible with the new version.
Process of doing database upgrade are as follows:-
·         Disable indexing so that indexer doesn’t try to run during the upgrade.
Add below .cfg file in following server path - [Liferay Home]/osgi/configs

com.liferay.portal.search.configuration.IndexStatusManagerConfiguration.cfg with following content :- indexReadOnly=true.

Note: By adding the above file you will avoid indexing and save time during the upgrade process. Once you have upgraded your portal, remove that property or set it to false so that you can index all objects from control panel.

Note: Make sure all your database indexes have been applied correctly. A missing index can cause an upgrade to really slow down.
                                                                               
Upgrade to Java 8:-
Liferay DXP comes with Java 8 as default Java Runtime.
Java 8 is quite mature at this point, and brings a multitude of new features that improve the quality of life of Java developers significantly, it will improve both overall performance and maintainability.

While applications written for Java 7 can be run on Java 8 (in most cases), it is recommended to budget time into your migration plan to allow for each of your applications to be ported and validated using Java 8.
Change in Deployment Process:-
Since Liferay architecture of Liferay DXP is changed, it has adopted OSGi framework container which is based on modules based application. Due to OSGi container the deployment process has been changed based on different approaches.

Deployment process with different approaches.

WARs are traditional web apps to which we are all accustomed. WARs are not recommended in Liferay DXP because you lose access to any service that has been deployed to the OSGi container, though they can still access Liferay’s core services.

Bundles/Modules are plugins you’ve converted to an OSGi bundle. They are just simple
Java JARs with OSGi metadata. Bundles can only be deployed into the OSGi container.
Bundles cannot access services deployed as WARs besides Liferay’s core services. This is the recommended approach for all new development and will be the approach Liferay takes for all new development.

WABs are web archive bundles. If you deploy a WAR to the OSGi container, Liferay will convert the WAR into a WAB. This will give you all the benefits of a bundle without doing the conversion.
This is the recommended approach for deploying legacy applications built for older versions of Liferay.

The Liferay auto deploy directory now deploys to the OSGi container by default. The only way to deploy to your web application’s deploy folder is to do this manually through a direct deploy.
Many of our tools will directly deploy to the OSGi container.

Note: If you plan to cluster your servers, OSGi bundles may provide an additional hurdle if you rely on your app server’s administrative tools to do cluster deployment as those tools are not able to deploy to our OSGi container. As a current workaround, Liferay provide with Cluster Deployment Helper. This tool will take any number of files and bundle them into a WAR. The WAR will copy the files into Liferay’s deploy folder when it is deployed and then uninstall itself. You can then use the WAR with any app server administration tool.

Search:-
Liferay DXP comes with Solr and embedded Elasticsearch search engine. Elasticsearch will not be supported for production server. There is a choice Elasticsearch (non-embedded) or Slor as your search provider.
Basically you will be required separate search server to maintain the whole Liferay portal to work smoothly.

Monday, November 21, 2016

Fetching list of files in java / vm from specific folder in Liferay

We will have a requirement like we need to fetch the files from a specific folder of DLFile then for this type of requirement, the below code will be helpful to you.


Long parentFolderId = DLFolderConstants.DEFAULT_PARENT_FOLDER_ID;
DLFolder folder = DLFolderLocalServiceUtil.getFolder(groupId, parentFolderId, dirName);
ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest.getAttribute(WebKeys.THEME_DISPLAY);
List fileEntryService = null;
try {
fileEntryService = DLFileEntryLocalServiceUtil.getFileEntries(themeDisplay.getScopeGroupId(),folder.getFolderId(),-1, -1, null);
} catch (SystemException e) {
e.printStackTrace();
}
for(DLFileEntry fileEntryObj : fileEntryService){
System.out.println(fileEntryObj.getTitle());
}


To fetch in VM file we can use this code :-

#set($service = $serviceLocator.findService("com.liferay.portlet.documentlibrary.service.DLFileEntryLocalService"))
#set($gid = $getterUtil.getLong($request.get("theme-display").get("scope-group-id"))) 
#set($fid = $getterUtil.getLong($folderId.getData())) 
#set($files = $service.getFileEntries($gid, $fid)) 
#foreach($doc in $files) 
#set($uet = $httpUtil.encodeURL($htmlUtil.unescape($doc.getTitle()))) 
$doc.getTitle()
#end

Sunday, November 13, 2016

Fetching Tag Based Documents or Web Contents from Assets

Sometimes we will have the requirement like we need to fetch the documents which are specifically tagged with some tag name. Then no worries below code will help you to fetch the tag based documents from DLFile and also to fetch the tag based web content from Journal Article.

Java Code :-

String[] tagNames = {"get announcements"};

// Getting the ids of journalarticle and DLFille
 long[] requiredClassIds = {PortalUtil.getClassNameId(JournalArticle.class.getName()), PortalUtil.getClassNameId(DLFileEntry.class.getName())};

AssetEntryQuery assetEntryQuery = new AssetEntryQuery();
          assetEntryQuery.setAllTagIds(AssetTagLocalServiceUtil.getTagIds(groupId, tagNames));
         assetEntryQuery.setClassNameIds(requiredClassIds);

List assetEntryList = AssetEntryLocalServiceUtil.getEntries(assetEntryQuery);

for (AssetEntry ae : assetEntryList) {
      if(JournalArticle.class.getName().equalsIgnoreCase(ae.getClassName())){

           JournalArticle wc = JournalArticleLocalServiceUtil.getArticle(groupId, String.valueOf(ae.getClassPK() - 2));

             System.out.println("AnnouncementsPortlet : render : found web content name ::"+wc.getUrlTitle());

   } else if(DLFileEntry.class.getName().equalsIgnoreCase(ae.getClassName())){

    DLFileEntry dl =  DLFileEntryLocalServiceUtil.getDLFileEntry(ae.getClassPK());

    }

}

         

Monday, September 26, 2016

Multiple database connection in Liferay

Liferay allows us to connect to multiple database at the same time. Follow the below steps for that.

1. In portal-ext.properties file make a entry.

--------------------------------------------------------------------

// default entry for default database connection

jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.username=root
jdbc.default.password=root
jdbc.default.url=jdbc\:mysql\://localhost/defaultdb?useUnicode\=true&characterEncoding\=UTF-8&useFastDateParsing\=false

// new entries for external db connection it will be connected by giving a entry in ext-spring.xml

jdbc.external.driverClassName=com.mysql.jdbc.Driver
jdbc.external.username=root
jdbc.external.password=root
jdbc.external.url=jdbc:mysql://localhost/externaldb?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false

--------------------------------------------------------------------

2) As we are using service-builder, it means that you need new tables other than liferay default DB. So it requires for you to create new plugins project and in that you need to create service.xml under webapps/WEB-INF and with the help of ANT(ant build-service) or MAVEN (mvn liferay:build-service) you will able to create full structure for your service. But still it is pointing to the default DB. 

Note:- In externaldb you have to create tables manualy.


Now you need to create a new file ext-spring.xml under WEB-INF/src/META-INF dir. Inside META-INF folder you will find couple of xml files whose entry will be there in liferay portal.properties.If you notice the order of xml file loading in portal.properties file, then you will find that the last file is ext-spring.xml is loaded. So we will now create ext-spring.xml and putting all transaction,datasource and sessionfactory related changed on that file as below :-

--------------------------------------------------------------------
<?xml version="1.0"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

<aop:config>
<aop:pointcut id="transactionOperation" expression="bean(*Service.impl)" />
<aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionOperation" />
</aop:config>

<bean id="basePersistence" abstract="true">
<property name="dataSource" ref="anotherDataSource" />
<property name="sessionFactory" ref="anotherSessionFactory" />
</bean>

<bean id="transactionAdvice" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="anotherTransactionManager" />
<property name="transactionAttributeSource">
<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
<constructor-arg>
<bean class="com.liferay.portal.spring.annotation.PortalTransactionAnnotationParser" />
</constructor-arg>
</bean>
</property>
</bean>

<bean id="anotherHibernateSessionFactory" class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration" lazy-init="true">
<property name="dataSource" ref="anotherDataSource" />
</bean>

<bean id="anotherSessionFactory" class="com.liferay.portal.dao.orm.hibernate.SessionFactoryImpl" lazy-init="true">
<property name="sessionFactoryImplementor" ref="anotherHibernateSessionFactory" />
</bean>

<bean id="anotherTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" lazy-init="true">
<property name="dataSource" ref="anotherDataSource" />
<property name="globalRollbackOnParticipationFailure" value="false" />
<property name="sessionFactory" ref="anotherHibernateSessionFactory" />
</bean>

<bean id="anotherDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
<property name="targetDataSource">
<bean class="com.liferay.portal.dao.jdbc.util.DataSourceFactoryBean">
<property name="propertyPrefix" value="jdbc.external." />
</bean>
</property>      
    </bean>

</beans>

--------------------------------------------------------------

3) Now you need to modify the existing service.xml as follows :-

---------------------------------------------------------------------------

<service-builder package-path="com.external.liferay">
<namespace>external</namespace>
<entity data-source="anotherDataSource" local-service="true" name="externaldb" remote-service="false" session-factory="anotherSessionFactory" tx-manager="anotherTransactionManager">
......
......
</entity>
</service-builder>

---------------------------------------------------------


The data-source value specifies the data source target that is set to the persistence class. The default value is the Liferay data source. This is used in conjunction with session-factory. 

The session-factory value specifies the session factory that is set to the persistence class. The default value is the Liferay session factory. This is used in conjunction with data-source. 

The tx-manager value specifies the transaction manager that Spring uses. The default value is the Spring Hibernate transaction manager that wraps the Liferay data source and session factory. 

If the local-service value is true, then the service will generate the local interfaces for the service. The default value is false.

If the remote-service value is true, then the service will generate remote interfaces for the service. The default value is true.

You can use the local-service and remote-service attribute according to your needs.











Liferay DXP JNDI Data Source Cofiguration

 This Blog will help us to learn about the JNDI Data Source Configuration in Liferay DXP. We have tested this with Liferay 7.3 with Tomcat. ...