Monday, January 12, 2015

DateTime plicker



1.    Introduction

Alloy UI has been supporting DatePicker widget but it does not have ability to choose time. That’s why we need to find another widget that meets our requirement. The timepicker addon adds a timepicker to jQuery UI Datepicker, thus the datepicker and slider components (jQueryUI) are required for using any of these. In addition all datepicker options are still available through the timepicker addon

2. Usage.

2.1. Option


The timepicker does inherit all options from datepicker. However, there are many options that are shared by them both, and many timepicker only options.

2.1.1. Localization Options


currentText
Default: "Now", A Localization Setting - Text for the Now button.
closeText
Default: "Done", A Localization Setting - Text for the Close button.
amNames
Default: ['AM', 'A'], A Localization Setting - Array of strings to try and parse against to determine AM.
pmNames
Default: ['PM', 'P'], A Localization Setting - Array of strings to try and parse against to determine PM.
timeFormat
Default: "HH:mm", A Localization Setting - String of format tokens to be replaced with the time.See Formatting.
timeSuffix
Default: "", A Localization Setting - String to place after the formatted time.


timeOnlyTitle
Default: "Choose Time", A Localization Setting - Title of the wigit when using only timepicker.
timeText
Default: "Time", A Localization Setting - Label used within timepicker for the formatted time.
hourText
Default: "Hour", A Localization Setting - Label used to identify the hour slider.
minuteText
Default: "Minute", A Localization Setting - Label used to identify the minute slider.
secondText
Default: "Second", A Localization Setting - Label used to identify the second slider.
millisecText
Default: "Millisecond", A Localization Setting - Label used to identify the millisecond slider.
microsecText
Default: "Microsecond", A Localization Setting - Label used to identify the microsecond slider.
timezoneText
Default: "Timezone", A Localization Setting - Label used to identify the timezone slider.
isRTL
Default: false, A Localization Setting - Right to Left support.

2.1.2. Alt Field Options


altFieldTimeOnly
Default: true - When altField is used from datepicker altField will only receive the formatted time and the original field only receives date.
altSeparator
Default: (separator option) - String placed between formatted date and formatted time in the altField.
altTimeSuffix
Default: (timeSuffix option) - String always placed after the formatted time in the altField.
altTimeFormat
Default: (timeFormat option) - The time format to use with the altField.

2.1.3. Timezone Options

 

timezoneList
Default: [generated timezones] - An array of timezones used to populate the timezone select. Can be an array of values or an array of objects: { label: "EDT", value: -240 }. The value should be the offset number in minutes. So "-0400" which is the format "-hhmm", would equate to -240 minutes.

2.1.4. Time Field Options.

controlType

Default: 'slider' - Whether to use 'slider' or 'select'. If 'slider' is unavailable through jQueryUI, 'select' will be used. For advanced usage you may pass an object which implements "create", "options", "value" methods to use controls other than sliders or selects. See the _controls property in the source code for more details.

showHour

Default: null - Whether to show the hour control. The default of null will use detection from timeFormat.

showMinute

Default: null - Whether to show the minute control. The default of null will use detection from timeFormat.

showSecond

Default: null - Whether to show the second control. The default of null will use detection from timeFormat.

showMillisec

Default: null - Whether to show the millisecond control. The default of null will use detection from timeFormat.

showMicrosec

Default: null - Whether to show the microsecond control. The default of null will use detection from timeFormat.

showTimezone

Default: null - Whether to show the timezone select.

showTime

Default: true - Whether to show the time selected within the datetimepicker.

stepHour

Default: 1 - Hours per step the slider makes.

stepMinute

Default: 1 - Minutes per step the slider makes.

stepSecond

Default: 1 - Seconds per step the slider makes.

stepMillisec

Default: 1 - Milliseconds per step the slider makes.

stepMicrosec

Default: 1 - Microseconds per step the slider makes.

hour

Default: 0 - Initial hour set.

minute

Default: 0 - Initial minute set.

second

Default: 0 - Initial second set.

millisec

Default: 0 - Initial millisecond set.

microsec


Default: 0 - Initial microsecond set. Note: Javascript's native Date object does not natively support microseconds. Timepicker adds ability to simply Date.setMicroseconds(m) and Date.getMicroseconds(). Date comparisons will not acknowledge microseconds. Use this only for display purposes.

timezone

Default: null - Initial timezone set. This is the offset in minutes. If null the browser's local timezone will be used. If you're timezone is "-0400" you would use -240. For backwards compatibility you may pass "-0400", however the timezone is stored in minutes and more reliable.

hourMin

Default: 0 - The minimum hour allowed for all dates.

minuteMin

Default: 0 - The minimum minute allowed for all dates.

secondMin

Default: 0 - The minimum second allowed for all dates.

millisecMin

Default: 0 - The minimum millisecond allowed for all dates.

microsecMin

Default: 0 - The minimum microsecond allowed for all dates.

hourMax

Default: 23 - The maximum hour allowed for all dates.

minuteMax

Default: 59 - The maximum minute allowed for all dates.

secondMax

Default: 59 - The maximum second allowed for all dates.

millisecMax

Default: 999 - The maximum millisecond allowed for all dates.

microsecMax

Default: 999 - The maximum microsecond allowed for all dates.

hourGrid

Default: 0 - When greater than 0 a label grid will be generated under the slider. This number represents the units (in hours) between labels.

minuteGrid

Default: 0 - When greater than 0 a label grid will be generated under the slider. This number represents the units (in minutes) between labels.

secondGrid

Default: 0 - When greater than 0 a label grid will be genereated under the slider. This number represents the units (in seconds) between labels.

millisecGrid

Default: 0 - When greater than 0 a label grid will be genereated under the slider. This number represents the units (in milliseconds) between labels.

microsecGrid

Default: 0 - When greater than 0 a label grid will be genereated under the slider. This number represents the units (in microseconds) between labels.

 

2.1.5. Other Options

showButtonPanel

Default: true - Whether to show the button panel at the bottom. This is generally needed.

timeOnly

Default: false - Hide the datepicker and only provide a time interface

onSelect

Default: null - Function to be called when a date is chosen or time has changed (parameters: datetimeText, datepickerInstance).

alwaysSetTime

Default: true - Always have a time set internally, even before user has chosen one.

separator

Default: " " - When formatting the time this string is placed between the formatted date and formatted time.

 


2.2. Formatting .


The default format is "HH:mm". To use 12 hour time use something similar to: "hh:mm tt". When both "t" and lower case "h" are present in the timeFormat, 12 hour time will be used.
H
Hour with no leading 0 (24 hour)
HH
Hour with leading 0 (24 hour)
h
Hour with no leading 0 (12 hour)
hh
Hour with leading 0 (12 hour)
m
Minute with no leading 0
mm
Minute with leading 0
s
Second with no leading 0
ss
Second with leading 0
l
Milliseconds always with leading 0
c
Microseconds always with leading 0
t
a or p for AM/PM
T
A or P for AM/PM
tt
am or pm for AM/PM
TT
AM or PM for AM/PM
z
Timezone as defined by timezoneList
Z
Timezone in Iso 8601 format (+04:45)

3. Example

3.1. Basic Initializations

Add a simple datetimepicker to jQuery UI's datepicker
$('#basic_example_1').datetimepicker();


Add only a timepicker:
$('#basic_example_2').timepicker();

Format the time:
$('#basic_example_3').datetimepicker({
         timeFormat: "hh:mm tt"
});

3.2. Using Timezones

Simplest timezone usage:
$('#timezone_example_1').datetimepicker({
         timeFormat: 'hh:mm tt z'
});

Define your own timezone options:
$('#timezone_example_2').datetimepicker({
         timeFormat: 'HH:mm z',
         timezoneList: [ 
                          { value: -300, label: 'Eastern'}, 
                          { value: -360, label: 'Central' }, 
                          { value: -420, label: 'Mountain' }, 
                          { value: -480, label: 'Pacific' } 
                 ]
});

You may also use timezone string abbreviations for values. This should be used with caution. Computing accurate javascript Date objects may not be possible when trying to retrieve or set the date from timepicker (see setDate and getDate examples below). For simple input values however this should work.
$('#timezone_example_3').datetimepicker({
         timeFormat: 'HH:mm z',
         timezone: 'MT',
         timezoneList: [ 
                          { value: 'ET', label: 'Eastern'}, 
                          { value: 'CT', label: 'Central' }, 
                          { value: 'MT', label: 'Mountain' }, 
                          { value: 'PT', label: 'Pacific' } 
                 ]
});

3.2. Slider Modifications

Add a grid to each slider:
$('#slider_example_1').timepicker({
         hourGrid: 4,
         minuteGrid: 10,
         timeFormat: 'hh:mm tt'
});

Set the interval step of sliders:
$('#slider_example_2').datetimepicker({
         timeFormat: 'HH:mm:ss',
         stepHour: 2,
         stepMinute: 10,
         stepSecond: 10
});

Add sliderAccess plugin for touch devices
$('#slider_example_3').datetimepicker({
         addSliderAccess: true,
         sliderAccessArgs: { touchonly: false }
});

Use dropdowns instead of sliders. By default if slider is not available dropdowns will be used.
$('#slider_example_4').datetimepicker({
         controlType: 'select',
         timeFormat: 'hh:mm tt'
});

Wednesday, January 7, 2015

Receive file upload in Liferay portlet

Upload

Using UploadPortletRequest to receive file input stream:

UploadPortletRequest uploadRequest = PortalUtil.getUploadPortletRequest(resourceRequest);

long                  fileSize = uploadRequest.getSize("field_name");
InputStream              is = uploadRequest.getFileAsStream("field_name");
String          mimeType = uploadRequest.getContentType("field_name");
String sourceFileName = uploadRequest.getFileName("field_name");

Save

To create file in Document and Media Library, using this one:

ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
ServiceContext serviceContext = ServiceContextFactory.getInstance(request);
User currentUser = PortalUtil.getUser(request);

// with default repository, repositoryId is equals to scopeGroupId
long repositoryId = themeDisplay.getScopeGroupId(); 
long userId = themeDisplay.getUserId();
long groupId = themeDisplay.getScopeGroupId();
long fileEntryTypeId = ParamUtil.getLong(serviceContext, "fileEntryTypeId", -1L);

Map<String, Fields> fieldsMap = new HashMap<String, Fields>();
// Now, add new one

DLFileEntry newFile = DLFileEntryLocalServiceUtil.addFileEntry(userId, groupId,
                                    repositoryId, folderId, sourceFileName, mimeType, title, "", "", fileEntryTypeId,
                                    fieldsMap, file, is, size, serviceContext);


DLFileEntryLocalServiceUtil.updateFileEntry(userId, newFile.getFileEntryId(),
                                    sourceFileName, mimeType, title, "", "", true, fileEntryTypeId, fieldsMap, null,
                                    null, uploadRequest.getSize(posterName), serviceContext);


In case, you want to create folder to save the file, this is how to do:
            // parentId = 0L means Root folder in Document Library
            long parentId = 0L; 

            // with default repository, repositoryId is equals to scopeGroupId
            long repositoryId = themeDisplay.getScopeGroupId();

            long userId = themeDisplay.getUserId();
            long groupId = themeDisplay.getScopeGroupId();

            DLFolder folder = DLFolderLocalServiceUtil.addFolder(userId, groupId, repositoryId, false, parentId, folderName, "", serviceContext);
            newFolderId = folder.getFolderId(); 


What about creating a list folder in hierarchy?
public long createFolders(String[] folders, ThemeDisplay themeDisplay, ServiceContext serviceContext) {
        int num = folders.length;

        long parentId = 0L;
        long newFolderId = 0L;

        for (int i = 0; i < num; i++) {
            newFolderId = MyUtilClass.findFolderByName(folders[i], parentId, themeDisplay.getScopeGroupId());
            if (newFolderId == -1) {
                newFolderId =
MyUtilClass.createFolder(folders[i], parentId, themeDisplay, serviceContext);
            }
            parentId = newFolderId;
        }

        return newFolderId;
    }
 

Get Link

To get file URL:
 
/* format file url: domain/documents/[groupid]/[folderid]/[fileName]/[uuid]
* e.g: http://localhost:8080/documents/10828/22503/Penguins2_1390451913869.JPG/0da81b4e-37cf-45a4-9872-8ac3447d9bba
* */
                            

String fileUrl = themeDisplay.getPortalURL() + themeDisplay.getPathContext() + SLASH + "documents"
                                    + SLASH + themeDisplay.getScopeGroupId() + SLASH + folderId + SLASH
                                    + HttpUtil.encodeURL(HtmlUtil.unescape(title)) + SLASH + newFile.getUuid();

Using Spring in Liferay portlet

In src/main/resources folder, create META-INF folder, inside this folder, create ext-spring.xml file. This file contains bean definition, like below:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:oxm="http://www.springframework.org/schema/oxm"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:jms="http://www.springframework.org/schema/jms"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="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-3.0.xsd
        http://www.springframework.org/schema/oxm
        http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd
        http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
        ">
       
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
           <list>
               <value>/WEB-INF/config/props.properties</value>
            </list>
        </property>
    </bean>
   
    <!-- Some bean -->
    <bean id="myBean" class="com.example.MyBean" /> 
</beans>


Also, in src/main/resources folder, create service.properties file:

##
## Properties Override
##

    #
    # Specify where to get the overridden properties. Updates should not be made
    # on this file but on the overridden version of this file.
    #
    include-and-override=${base.path}/service-ext.properties


##
## Spring
##

    #
    # Input a list of comma delimited Spring configurations. These will be
    # loaded after the bean definitions specified in the
    # portalContextConfigLocation parameter in web.xml.
    #
    spring.configs=\
        WEB-INF/classes/META-INF/base-spring.xml,\
        \
        WEB-INF/classes/META-INF/hibernate-spring.xml,\
        WEB-INF/classes/META-INF/infrastructure-spring.xml,\
        \
        WEB-INF/classes/META-INF/cluster-spring.xml,\
        \
        WEB-INF/classes/META-INF/portlet-spring.xml,\
        \
        WEB-INF/classes/META-INF/dynamic-data-source-spring.xml,\
        WEB-INF/classes/META-INF/shard-data-source-spring.xml,\
        \
        WEB-INF/classes/META-INF/ext-spring.xml


Now, your bean will loaded every time Liferay started.

In your *LocalServiceUtil, if you would like to use the bean in ext-spring.xml file, use this code:

public class YourServiceUtil {
     public static void someFunc() {
        getService().someFunc();
    }
   
    public static void clearService() {
        _service = null;
    }

    public static YourServiceImpl getService() {
        if (_service == null) {
           
_service = (YourServiceImpl ) PortletBeanLocatorUtil
                    .locate(ClpSerializer.getServletContextName(), "your_bean_name");
        }

        return _service;
    }

    private static YourServiceImpl _service;
}


ClpSerializer.getServletContextName() is a class return the contextName of the context where bean located. Usually, it is your project name.

Tuesday, January 6, 2015

Materialized View - Oracle

Materialized view creates a pre-join view that will help much on improving query performance.
With materialized, we have REFRESH FAST, COMPLETE, FORCE, NEVER options and ON COMMIT or ON DEMAND modes.
Reference: http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_6002.htm#SQLRF01302
http://its-all-about-oracle.blogspot.com/2013/07/refreshing-materialized-view.html

With Refresh Fast

We have to create View log with Row Id to keep changes from master table. After that, these changes will be updated to materialized view.

For example:

create materialized view log on atm_program with rowid, sequence ;

create materialized view log on atm_programtitle with rowid, sequence ;


"sequence" here may be useful when there are many changes occur at the same time. We need assure that it is in sequence.

Then create materialized view (cannot using LEFT JOIN or INNER JOIN, have to use old style):

CREATE MATERIALIZED VIEW MV_PROGRAMTABLE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT t.ticketid,
    ts.statusname,
    p.programid,
    pt.title,
    p.programtype,
    p.originalstartairdate AS originalstartairdate,
    pt.language,
    t.statusid,
    t.createdate,
    t.tickettype,
    p.primaryimageurl,
    p.primarythumbnailurl,
    p.posterstatus,
    p.rowid p_rowid,
    pt.rowid pt_rowid,
    t.rowid t_rowid,
    ts.rowid ts_rowid
  FROM atm_program p, atm_programtitle pt, atm_ticket t, atm_ticketstatus ts

  WHERE p.programid = pt.programid(+)

  AND t.programid(+) = p.programid

  AND ts.statusid(+)              = t.statusid;


(+) mean optional. So p.programid = pt.programid(+) is the same LEFT JOIN. RowId is also need to be included.

Note: Any changes will be put in view log before update to view. It happens whenever INSERT, UPDATE, DELETE. So it will be very slow.

With Refresh on Demand

Data in view must be refresh manually. It can be done by code using Store procedure.
For example:


Create Materialized view: 
---------Create progam table view
CREATE MATERIALIZED VIEW MV_PROGRAMTABLE
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH ON DEMAND
AS
SELECT /*+ PARALLEL(program, 4) PARALLEL(programtitle, 4) */
t.ticketid,
ts.statusname,
p.programid,
pt.title,
p.programtype,
p.originalstartairdate AS originalstartairdate,
pt.LANGUAGE,
t.statusid,
t.createdate,
t.tickettype,
p.primaryimageurl,
p.primarythumbnailurl,
p.posterstatus
FROM program p
LEFT JOIN programtitle pt
ON p.programid = pt.programid
LEFT JOIN ticket t
ON t.programid = p.programid
LEFT JOIN ticketstatus ts
ON ts.statusid = t.statusid;
 

Create Store procedure:
-- Create program refresh store procedure
create or replace
PROCEDURE PROC_REFRESH_MV_PROGRAMTABLE
IS
BEGIN
dbms_mview.refresh('MV_PROGRAMTABLE');
END PROC_REFRESH_MV_PROGRAMTABLE;

In code,

    public void refreshDataForProgramMView() {
       
        ConfigUtil config = ConfigUtil.getInstance();
       
        String programStoreName = config.getValue("storeProcedure.refresh.ProgramMV");
       
        Query query = em.createNativeQuery("{call "+ programStoreName +"()}");

        query.executeUpdate();

    }


In this case, "em" is entityManager of JPA. ConfigUtil points to configuration properties file. It's used to get the Store procedure name.

"refreshDataForProgramMView" function is available to call whenever needed.


Monday, January 5, 2015

Using BlockUI

It is great to use blockUI to temporarily disable browser screen, avoid unwanted action from user (while running something for example).

Reference: http://malsup.com/jquery/block/