Sunday 26 March 2017

Reorder Repeatable Structure Field Content



Reorder Repeatable Structure Field Content for Liferay

Current Problem:

Currently “Repeatable:true” enables content writers to add numerous content as per their requirements. The problem arises when you want to re-order these components while “Add or Remove” functions. 

As of now, users do not have this functionality and content editors face significant challenges to get things done rapidly.

Solution:

Reorder Repeatable Structure Field Content is an absolute solution that allows users to re-order content on the go.
Once added, this component allows users to modify and re-order content with UP and DOWN arrows to Add or Remove content fields as per their requirements. 

How to configure:
  • Step 1: Paste the War file in deploy folder on Tomcat Server  
  • Step 2: Add or Remove any repeatable component by click on (+) and (-) Button to add or remove any repeatable content. 
  • Step 3: You will be able to see Up and Down Arrow keys on the left side of (+) and (-) Button and you can move Up and Down any content by clicking them. 

Download component war file by click on below button

 





GitHub URL

https://github.com/knowarth-technologies/reorder-repeatable-structure-field.git














Thursday 2 February 2017

Web Content Structure Field Max Repeatable Component for Liferay



KA Structure Field Max Repeatable Component for Liferay

Download component war file by click on below button


Problem

Creating a structure with “repeatable: true”, it enables content writer to add numerous content box as per requirement. But what if you want to restrict the number of content box & restrict the content writer with a specific number of content box.  

Solution

KA Max Repeatable component provides the solution. With this component added you get the new setting option “max repeatable” while creating structure and you can set the appropriate value for that.

How to Configure:
Add following property to portal-ext.properties file and restart server
xml.validation.enabled=false  
Paste the War file in deploy folder on Tomcat Server
Set the value of “max repeatable” attribute on the repeatable field.




So now while creating content if the content writer tries to add more components or content box component then specified value it will restrict the user and display an appropriate notification.







Thursday 21 May 2015

Database Sharding

     

Database Sharding with Liferay

 


      Database sharding is a  horizontal partition of your database. That smaller, faster, more easily managed partitions are called data shards that may be located at diffrent database server or physical location. As per my knowledge Google,Wikipedia,Facebook and  all use database sharding.


Here I will discuss database sharding with Liferay, Sharding available in liferay from version 5.2.3+ for handling data between multiple liferay portal instances.


Lets learn how to configure database sharding with 4 instances. In our example scenario we want to create four portal instances. We want to store data of each portal instance to separate database. It is assumed that MySQL is installed on local environment and MySQL Driver jar is copied in tomcat lib directory. This steps refer Liferay 6.2 CE GA2 version.

By default liferay allows three shards but we can configure more than three shards and Liferay assigns shard to portal instance on round ribbon bases but we can also apply database selection at portal instance creation by setting below property in portal-ext.properties file.

shard.selector=com.liferay.portal.dao.shard.ManualShardSelector.

Here are the steps to configure database sharding on local Liferay environment.

Step 1 :

           Database sharding feature in Liferay works with portal instances. So on Local environment we will need to create multiple portal instances. To create multiple portal instance, we need to have multiple domains. On local environment we can add multiple domains by editing hosts file. So add following entries in hosts file. 

Host file Location for windows :

C:\Windows\System32\drivers\etc\hosts

Add just following three lines in host file.

127.0.0.1       abc.com
127.0.0.1       def.com
127.0.0.1       ghi.com


        Above step maps local host ip to three domains. By default liferay creates one portal instance and it is mapped to localhost. So we will create three more instances and map them with above selected domains respectively.

Step 2 :  Following code for portal-ext.properties file.

#SHARD 1 Configuration
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost/hbe?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=root
jdbc.default.password=

#SHARD 2 Configuration
jdbc.one.driverClassName=com.mysql.jdbc.Driver
jdbc.one.url=jdbc:mysql://localhost/abc?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.one.username=root
jdbc.one.password=

#SHARD 3 Configuration
jdbc.two.driverClassName=com.mysql.jdbc.Driver
jdbc.two.url=jdbc:mysql://localhost/def?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.two.username=root
jdbc.two.password=

#SHARD 4 Configuration
jdbc.three.driverClassName=com.mysql.jdbc.Driver
jdbc.three.url=jdbc:mysql://localhost/ghi?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.three.username=root
jdbc.three.password=

shard.available.names=default,one,two,three
shard.selector=com.liferay.portal.dao.shard.ManualShardSelector
value.object.entity.cache.enabled.com.liferay.portal.model.Contact=false

#Spring configuration files to be loadded. By adding shard-data-source-spring.xml in the list database sharding feature
#can be enabled
spring.configs=\
        META-INF/base-spring.xml,\
        \
        META-INF/hibernate-spring.xml,\
        META-INF/infrastructure-spring.xml,\
        META-INF/management-spring.xml,\
        \
        META-INF/util-spring.xml,\
        \
        META-INF/jpa-spring.xml,\
        \
        META-INF/executor-spring.xml,\
        \
        META-INF/audit-spring.xml,\
        META-INF/cluster-spring.xml,\
        META-INF/editor-spring.xml,\
        META-INF/jcr-spring.xml,\
        META-INF/ldap-spring.xml,\
        META-INF/messaging-core-spring.xml,\
        META-INF/messaging-misc-spring.xml,\
        META-INF/mobile-device-spring.xml,\
        META-INF/notifications-spring.xml,\
        META-INF/poller-spring.xml,\
        META-INF/rules-spring.xml,\
        META-INF/scheduler-spring.xml,\
        META-INF/scripting-spring.xml,\
        META-INF/search-spring.xml,\
        META-INF/workflow-spring.xml,\
        \
        META-INF/counter-spring.xml,\
        META-INF/mail-spring.xml,\
        META-INF/portal-spring.xml,\
        META-INF/portlet-container-spring.xml,\
        META-INF/staging-spring.xml,\
        META-INF/virtual-layouts-spring.xml,\
        META-INF/shard-data-source-spring.xml,\
        META-INF/ext-spring.xml
 
 

Step 3: Add "shard-data-source-spring.xml”  file to the following location .

liferay-portal-6.2-ce-ga2\tomcat-7.0.42\webapps\ROOT\WEB-INF\classes\META-INF\shard-data-source-spring.xml


shard-data-source-spring.xml 



<?xml version="1.0"?>

<beans 
  default-destroy-method="destroy" 
  default-init-method="afterPropertiesSet"
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:aop="http://www.springframework.org/schema/aop"
  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">

  <bean id="liferayDataSource" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource">
      <bean class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="targetSource" ref="shardDataSourceTargetSource" />
      </bean>
    </property>
  </bean>

  <bean id="liferayHibernateSessionFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="shardSessionFactoryTargetSource" />
  </bean>

  <!-- default shard -->
  <bean id="shardDataSource0" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource">
      <bean class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean">
        <property name="propertyPrefix" value="jdbc.default." />
      </bean>
    </property>
  </bean>

  <!-- shardOne -->
  <bean id="shardOne" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource">
      <bean class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean">
        <property name="propertyPrefix" value="jdbc.one." />
      </bean>
    </property>
  </bean>

    <!-- shardTwo -->
  <bean id="shardTwo" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource">
      <bean class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean">
        <property name="propertyPrefix" value="jdbc.two." />
      </bean>
    </property>
  </bean>
  
    <!-- shardThree -->
  <bean id="shardThree" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
    <property name="targetDataSource">
      <bean class="com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean">
        <property name="propertyPrefix" value="jdbc.three." />
      </bean>
    </property>
  </bean>
  <bean id="shardDataSourceTargetSource" class="com.liferay.portal.dao.shard.ShardDataSourceTargetSource">
    <property name="dataSources">
      <map>
        <entry>
          <key>
            <value>default</value>
          </key>
          <ref bean="shardDataSource0" />
        </entry>
        <entry>
          <key>
            <value>shard1</value>
          </key>
          <ref bean="shardOne" />
        </entry>
  <entry>
          <key>
            <value>shard2</value>
          </key>
          <ref bean="shardTwo" />
        </entry>
  <entry>
          <key>
            <value>shard3</value>
          </key>
          <ref bean="shardThree" />
        </entry>
      </map>
    </property>
  </bean>
  
  <bean id="shardSessionFactoryTargetSource" 
        class="com.liferay.portal.dao.shard.ShardSessionFactoryTargetSource">
    <property name="shardDataSourceTargetSource" ref="shardDataSourceTargetSource" />
  </bean>
  <bean id="com.liferay.portal.kernel.dao.jdbc.MappingSqlQueryFactoryUtil" 
        class="com.liferay.portal.kernel.dao.jdbc.MappingSqlQueryFactoryUtil">
    <property name="mappingSqlQueryFactory">
      <bean class="com.liferay.portal.dao.shard.ShardMappingSqlQueryFactoryImpl" />
    </property>
  </bean>
  <bean id="com.liferay.portal.kernel.dao.jdbc.SqlUpdateFactoryUtil" 
        class="com.liferay.portal.kernel.dao.jdbc.SqlUpdateFactoryUtil">
    <property name="sqlUpdateFactory">
      <bean class="com.liferay.portal.dao.shard.ShardSqlUpdateFactoryImpl" />
    </property>
  </bean>
  <bean id="com.liferay.portal.kernel.dao.shard.ShardUtil" 
        class="com.liferay.portal.kernel.dao.shard.ShardUtil">
    <property name="shard">
      <bean class="com.liferay.portal.dao.shard.ShardImpl">
        <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
      </bean>
    </property>
  </bean>
  <bean id="com.liferay.portal.kernel.util.InfrastructureUtil" 
        class="com.liferay.portal.kernel.util.InfrastructureUtil">
    <property name="dataSource" ref="liferayDataSource" />
    <property name="mailSession" ref="mailSession" />
    <property name="shardDataSourceTargetSource" ref="shardDataSourceTargetSource" />
    <property name="shardSessionFactoryTargetSource" ref="shardSessionFactoryTargetSource" />
    <property name="transactionManager" ref="liferayTransactionManager" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardAdvice" 
        class="com.liferay.portal.dao.shard.advice.ShardAdvice">
    <property name="shardDataSourceTargetSource" ref="shardDataSourceTargetSource" />
    <property name="shardSessionFactoryTargetSource" ref="shardSessionFactoryTargetSource" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardCompanyAdvice" class="com.liferay.portal.dao.shard.advice.ShardCompanyAdvice">
    <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardPortletAdvice" class="com.liferay.portal.dao.shard.advice.ShardPortletAdvice">
    <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardPersistenceAdvice" class="com.liferay.portal.dao.shard.advice.ShardPersistenceAdvice">
    <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" class="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice">
    <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardIterativelyAdvice" class="com.liferay.portal.dao.shard.advice.ShardIterativelyAdvice">
    <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
  </bean>
  <bean id="com.liferay.portal.dao.shard.advice.ShardParameterAdvice" class="com.liferay.portal.dao.shard.advice.ShardParameterAdvice">
    <property name="shardAdvice" ref="com.liferay.portal.dao.shard.advice.ShardAdvice" />
  </bean>
  <aop:config proxy-target-class="false">
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardCompanyAdvice" 
         pointcut="bean(com.liferay.portal.service.CompanyLocalService)" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardPortletAdvice" 
         pointcut="bean(com.liferay.portal.service.PortletLocalService)" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardPersistenceAdvice" 
         pointcut="bean(*Persistence) || bean(*Finder)" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" 
         pointcut="execution(void com.liferay.portal.convert.messaging.ConvertProcessMessageListener.receive(..))" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" 
         pointcut="execution(void com.liferay.portal.events.StartupHelper.updateIndexes())" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" 
         pointcut="execution(void com.liferay.portal.events.StartupHelper.upgradeProcess(int))" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardIterativelyAdvice" 
         pointcut="execution(void com.liferay.portal.events.StartupHelper.verifyProcess(boolean))" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" 
         pointcut="execution(* com.liferay.portal.service.ReleaseLocalService.getBuildNumberOrCreate())" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" 
         pointcut="execution(void com.liferay.portal.service.ServiceComponentLocalService.upgradeDB(..))" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardGloballyAdvice" 
         pointcut="execution(void com.liferay.portlet.journal.service.JournalArticleLocalService.checkArticles())" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardParameterAdvice" 
         pointcut="execution(* com.liferay.portal.service.AccountLocalService.getAccount(long, long))" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardParameterAdvice" 
         pointcut="execution(* com.liferay.portal.service.ResourceCodeLocalService.checkResourceCodes(long, String))" />
    <aop:advisor advice-ref="com.liferay.portal.dao.shard.advice.ShardParameterAdvice" 
         pointcut="execution(* com.liferay.portal.service.UserLocalService.searchCount(..))" />
  </aop:config>
</beans> 
 
 
 
 
 

Step 4 :  Now start the Lifeary portal server and access using http://localhost:8080. Liferay will show setup wizard to configure the portal. After you signed in to the portal if you check user_ table in test database you will find the test user. Which means 1st portal instance is mapped to default shard test.

Step 5 :  Now add three portal instances from Server Administration | Portal Instances section of control panel. While adding the instances make sure you use abc.com, def.com and ghi.com as web id. Here are the sample screenshots for





Step 6: Now access other three instances using http://abc.com:8080 , http://def.com:8080 and http://ghi.com:8080 URLs. You can sign in to the instances using test@abc.com, test@def.com and test@ghi.com user ids. Default password will be “test”. Now if we check user_ table in abc, def and ghi databases, we will find record of test@abc.com, test@def.com, and test@ghi.com users respectively.

So with above example we learned that each portal instance data is stored in seperate database.