Monday, January 5, 2015

Paging with Simple Pagination in Liferay

Reference: http://flaviusmatis.github.io/simplePagination.js/

In Liferay,

function renderPaginator(total, url, currentPage) {
    if(total > 0) {
        $(function() {
            $('#paginator').pagination({
                items: total,
                itemsOnPage: 20,
                cssStyle: 'light-theme',
                currentPage:currentPage,
                onPageClick : function(page) {
                    //update page
                }
            });
        });
        $('#page-no-result').html("");
 

    } else {
        $('#paginator').html("");
        $('#page-no-result').html(Liferay.Language.get("content.noresult"));
    }
}

Make a request in Liferay using AlloyUI

AUI().ready('aui-io-request', function(A) {
    Liferay.on(
             'event_name',
             function(data) {
                 var param = event.data;
                 if(param != null) {

                      //use blockUI to block screen
                     $.blockUI({ message: null }); 

                     A.io.request(searchUrl, {
                         data: {
                             keyword: param ,
                         },
                        dataType: 'json',
                        on: {
                            success : function() {
                                     // do something here

                                    $.unblockUI();
                            },
                            failure : function() {
                                $.unblockUI();
                            }
                        }
                    });
                 }

         })
});

To fire event, using:

Liferay.fire('event_name', {data: param });

References:
http://proliferay.com/alloy-ajax-liferay-portlet/ 

Encode and Decode param in Webservice

To encode, we do like this:

        ExternalWebServiceUtil.updateProgram(URLEncoder.encode(programId, "UTF-8"));

And for decoding, use:

        externalService.updateProgram(URLDecoder.decode(programId, "UTF-8"));

Create popup in Liferay

Liferay Dialog

function createDialog(param) {
    AUI().use(
            'liferay-portlet-url',
            'aui-dialog',
            'aui-dialog-iframe',
            function(A) {
                var url = Liferay.PortletURL.createRenderURL();
                url.setPortletId("portletName_WAR_contextName");
                url.setParameter("param", param);
                url.setWindowState('pop_up');
                var dialog = new A.Dialog({
                    id : 'mydialog',
                    centered : true,
                    title : 'Popup',
                    height : 'auto',
                    resizable : false,
                    modal : true,
                    scrollable : false,
                    destroyOnClose : true,
                    on : {
                        close : function() {
                            //do something here
                        },
                    }
                }).plug(A.Plugin.DialogIframe, {
                    uri : url,
                    iframeCssClass : 'dialog-iframe',
                }).render();
            });
}


In this case, we create url by using Liferay.PortletURL. If you want to create it in view.jsp, use:

<liferay-portlet:renderURL var="pagelLink"
    plid="<%=pageLayoutId%>"
    portletName="<%=portletName%>">
</liferay-portlet:renderURL>


with pageLayoutId got from:

    long pageLayoutId = 0l;
    if (PortletUtility.getPlid("Page Name") != null) {
        pageLayoutId = Long.valueOf(PortletUtility.getPlid("Page Name");
    }


If you want to add parameters to link, append this link with format like below:
&_PortletName_WAR_portletProjectName_paramName=paramValue

Ex: '&_ATMSeriesInfo_WAR_atmuiportlet_id=' + id

Liferay Popup

function showPopup(title, content, okLabel, cancelLabel, OKHandler, cancelHandler) {
    AUI().use('aui-dialog',
      function(A) {
        var buttons = [];
        if(okLabel) {
            var okBut = {
                    handler: function() {
                        if(OKHandler) {
                            OKHandler();
                        }
                        this.close();
                    },
                    label: okLabel
                  };
            buttons.push(okBut);
        }
       
        if(cancelLabel) {
            var cancelBut = {
                    handler: function() {
                        if(cancelHandler) {
                            cancelHandler();
                        }
                        this.close();
                    },
                    label: cancelLabel,
                  };
            buttons.push(cancelBut);
        }

        new A.Dialog(
          {
            bodyContent: content,
            buttons: buttons,
            centered: true,
            draggable: true,
            resizable: false,
            title: title,
            width: 400,
            height: 150,
            modal: true
          }
        ).render();
      }
    );
}


Liferay.Util javascript

For example creating a link display your account info in a popup:

<a href=\"javascript:Liferay.Util.openWindow({dialog: {destroyOnHide: true}, title: '" + LanguageUtil.get(pageContext, "my-account") + "', uri: '" + HtmlUtil.escape(myAccountURL) + "'});\">

Sunday, January 4, 2015

Connect external DB in Liferay

Sometimes, we need connect to external DB in Liferay. How to do it?

JNDI Name

In tomcat server:

In server.xml file in Server in Eclispe:

        <GlobalNamingResources>
              <!-- Editable user database that can also be used by UserDatabaseRealm
                     to authenticate users -->
              <Resource auth="Container" description="User database that can be updated and saved"
                     factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase"
                     pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase" />

              <Resource description="My DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
                     maxActive="20" maxIdle="10" maxWait="5000" name="jdbc/mypool"
                     password="mypass" testOnBorrow="true" type="javax.sql.DataSource"
                     url="jdbc:oracle:thin:@localhost:1521:mydb" username="myname"
                     validationQuery="SELECT 1 FROM DUAL" />

       </GlobalNamingResources>

In context.xml file in Server in Eclispe:

<!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
   
    <ResourceLink global="jdbc/mmtpool" name="jdbc/mypool" type="javax.sql.DataSource"/>

    <!-- Uncomment this to enable Comet connection tacking (provides events
         on session expiration as well as webapp lifecycle) -->
    <!--
    <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
    -->

The JNDI name highlighted in green must be the same with JNDI define in code.

Using Liferay util class and Hibnerate:

<!-- configuration for external db -->
    <bean id="myDataSourceTarget" class="com.liferay.portal.spring.jndi.JndiObjectFactoryBean"
        lazy-init="true">
        <property name="jndiName">
            <value>jdbc/mypool</value>
        </property>
    </bean>
    <bean id="myDataSource"
        class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource">
            <ref bean="myDataSourceTarget" />
        </property>
    </bean>
    <bean id="myHibernateSessionFactory"
        class="com.liferay.portal.spring.hibernate.PortletHibernateConfiguration">
        <property name="dataSource">
            <ref bean="myDataSource" />
        </property>
    </bean>
    <bean id="mySessionFactory" class="com.liferay.portal.dao.orm.hibernate.SessionFactoryImpl">
        <property name="sessionFactoryImplementor">
            <ref bean="myHibernateSessionFactory" />
        </property>
    </bean>
    <bean id="myTransactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="dataSource">
            <ref bean="myDataSource" />
        </property>
        <property name="sessionFactory">
            <ref bean="myHibernateSessionFactory" />
        </property>
    </bean>


In *FinderImpl file, add function like this:

        public int countTicket(String status, String priority, String ticketNo, String assigneeId)
            throws SystemException {

        Session session = null;

        try {
            // open a new hibernate session in normal case when you are opening
            // session for same entity
            session = openSession();
            // pull out our query from default.xml, created earlier
            String sql = CustomSQLUtil.get(COUNT_TICKET);
            // create a SQLQuery object
            SQLQuery query = session.createSQLQuery(sql);

            // Get query position instance
            QueryPos qPos = QueryPos.getInstance(query);
            qPos.add(status);
            qPos.add(priority);
            qPos.add(ticketNo);
            qPos.add(assigneeId);
            query.addScalar("total", Type.INTEGER);
            List results = (List) query.list();

            Integer count = (Integer) results.get(0);
            return count;


        } catch (Exception e) {
            throw new SystemException(e);
        } finally {
            closeSession(session);
        }


*FinderImpl class should extends from BasePersistenceImpl<Your_Entity> and implements *Finder.

Using Spring util class and JPA:

<!-- DataSource -->
    <jee:jndi-lookup id="dataSourceTarget" jndi-name="jdbc/mypool" expected-type="javax.sql.DataSource" />
      
    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource" ref="dataSourceTarget" />
    </bean>
       
    <!-- Entity Manager Factory for Spring Data JPA -->
    <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="showSql" value="false"/>
        <property name="generateDdl" value="false"/>
        <property name="database" value="ORACLE"/>
    </bean>
   
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
        <!-- spring based scanning for entity classes-->
        <property name="packagesToScan" value="com.example.dao.entity"/>
    </bean>
   

    <!-- Transaction Manager for Spring Data JPA -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>        
    </bean>
       
    <tx:annotation-driven transaction-manager="transactionManager"/>    


From now, we can use JPA Repository. Reference: http://www.petrikainulainen.net/spring-data-jpa-tutorial/ OR write your own query function, like below:

@PersistenceContext
protected EntityManager em;

public List getProgram() {

        String sql = "SELECT * FROM program";
        Query query = em.createNativeQuery(sql);
        return query.getResultList();
    }

Wednesday, December 31, 2014

Logback - SLF4J

Pom.xml file:

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${org.slf4j-version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${logback-version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback-version}</version>
        </dependency>



In src/main/resources folder, create logback.xml file. Put these configuration:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<configuration>
    <!-- File appender -->
     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <File>D:\mmt-ws-logs\mmt-ws-log.log</File>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
               <FileNamePattern>D:\mmt-ws-logs\mmt-ws-log.%d{yyyy-MM-dd}.log</FileNamePattern>
               <MaxHistory>30</MaxHistory>
          </rollingPolicy>
   
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{ISO8601} [%-5p] [%t] %c %X - %m%n</pattern>
        </encoder>
    </appender>
   
    <!-- Console appender -->
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{HH:mm:ss} %level [%thread] %logger [%file:%line] %msg%n</pattern>
        </encoder>
    </appender>

  <root level="INFO,ERROR">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>


In this case, we use RollingFileAppender to write log to file. It also recreate new file for new date.

For showing in Console, use ConsoleAppender.

Tuesday, December 30, 2014

Sequence in Oracle

Create Sequence

CREATE SEQUENCE customers_seq
 START WITH     1000
 INCREMENT BY   1
 NOCACHE
 NOCYCLE;
 
In case that we already have data in DB, use this snippet:

declare
    new_id number;
begin
   select NVL(max(id),0) + 1
   into   new_id
   from   my_table;

    execute immediate 'Create sequence my_seq
                       start with ' || new_id ||
                       ' increment by 1';
end;

/

Use Sequence

In Entity object:

    /** The auto id. */
    private Long autoId;

    /**
     * Gets the auto id.
     *
     * @return the auto id
     */
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sq")
    @SequenceGenerator(name = "sq", sequenceName = "my_seq", allocationSize=1)
    @Column(name = "AUTOID", unique = true, nullable = false, precision = 30, scale = 0)
    public Long getAutoId() {
        return this.autoId;
    }

    /**
     * Sets the auto id.
     *
     * @param autoId the new auto id
     */
    public void setAutoId(Long autoId) {
        this.autoId = autoId;
    }



GenerationType.SEQUENCE is specific for Oracle. Because Oracle uses Sequence strategy for create AutoId.

In @SequenceGenerator, the “allocationSize” is by default set to 50
And, by default, the “increment by” is set to 1.

Note:

It’s important to note that, the sequence generator work correctly, only when the “allocationSize” and the “increment by” are same, otherwise there is a possibility of getting the “unique constraint violation” exception. therefore, it is better to explicitly define “allocationSize” and “increment by”.