Sunday 5 November 2017

JDeveloper 12c is slow again. Attempt #2

This time I am trying to optimize freshly installed JDeveloper 12c (12.2.1.3.0). The laptop is the same, it is Dell Latitude with 16Gb RAM and Intel Core i7 @2.60GHz with Windows 10 64 bit OS.To make life easier, this time I decided to use http://gceasy.io/ an ML based GC tuning site. The tool gives tips where I have issues and makes all the tuning exercise an easy task.
I am using G1 garbage collector instead of CMS.

The outcome is perfect, the JDeveloper is now responds quick and the overall perception is good so far. My settings now as follows:
ide.conf:
AddVMOption -Xms2048M
AddVMOption -Xmx2048M

jdev.conf:
AddVMOption -XX:+UseStringCache
AddVMOption -XX:+OptimizeStringConcat
#AddVMOption -XX:+UseCompressedStrings
#AddVMOption -XX:+UseCompressedOops
AddVMOption -XX:+AggressiveOpts

AddVMOption -server
AddVMOption -XX:+UseG1GC
AddVMOption -XX:MaxGCPauseMillis=100
AddVMOption -XX:ParallelGCThreads=8
AddVMOption -XX:ConcGCThreads=2
AddVMOption -XX:InitiatingHeapOccupancyPercent=70
AddVMOption -XX:G1HeapRegionSize=48M
AddVMOption -XX:MetaspaceSize=256M

AddVMOption -XX:+PrintGCDetails
AddVMOption -XX:+PrintGCDateStamps
AddVMOption -XX:+PrintAdaptiveSizePolicy
AddVMOption -XX:+PrintTenuringDistribution
AddVMOption -Xloggc:c:\temp\soa_gc.log

Friday 23 December 2016

How to integrate CKEditor into an Oracle JET page

First of all you need to setup up your main.js file, it should look like below.
It is assumed, that ckeditor is available in js/libs/ckeditor folder.

requirejs.config, paths:

'ckeditor': 'libs/ckeditor/ckeditor',
'ckeditor-jquery': 'libs/ckeditor/adapters/jquery'

shim:
                 'ckeditor-jquery': {
                                    deps: ['jquery', 'ckeditor']
                                }
in the require block add 'ckeditor-jquery';

in your html file add, if you add the same construct into a div element, it just does not show anything.
within textarea tag add

id="id1" data-bind="jqueryUI:{component: 'ckeditor', value: value, skin: 'moono-lisa', toolbar: 'basic', uiColor : '#9AB8F3'}"

To change the toolbar add the following within the curly brackets

To change the toolbars add the fo

toolbarGroups:  [
                                {name: 'basicstyles', groups: ['basicstyles', 'cleanup']},
                               
                            ]

And you should see






Friday 16 December 2016

How to format JSON date in Oracle JET

Let's say that you have a JSON date in the following format
"createdDate" : "2016-03-01T13:00:00-08:00"

and you need to show on your web page created with Oracle JET.
To format the above date to a human readable format use the following javascript function:

self.getFormattedDate = function (requestedDate) {
                 
                    var dateOptions = {formatStyle: 'date', dateFormat: 'long'};  
                    var dateConverter = oj.Validation.converterFactory("datetime").createConverter(dateOptions);
                    var convertedDate = oj.IntlConverterUtils.dateToLocalIso(new Date(requestedDate));

                    return dateConverter.format(convertedDate);
                };

On UI side call it as follows.

data-bind="text: getFormattedDate(createdDate)"





Sunday 6 November 2016

Fixing ORABPEL-02117 Variable already declared. A variable with key "XXXX" is already declared in the current scope.

A surprise error message occurs after the successful deploy of the BPM project. To resolve it look for duplicate definitions in the BPMN process files. In my case I had:

<ns5:Conversation id="CONVERSATION155142191537" type="service_call">
          <ns5:ServiceCallConversationDefinition service="Services.Externals.GetApplicationData"/>
         </ns5:Conversation>
         <ns5:Conversation id="CONVERSATION176785361049" type="service_call">
          <ns5:ServiceCallConversationDefinition service="Services.Externals.GetApplicationData"/>
         </ns5:Conversation>

Removed the first occurrence and updated Conversation id to the value of the second occurrence and redeployed. The error has been resolved!

Tuesday 31 May 2016

QuickTips: MultiSelect LOV and limited number of list members

If your multiselect list refuses to show all the values of your list, then you can go to the page bindings, click on the iterator and change "RangeSize" to a higher value (by default it is 25).

Saturday 21 May 2016

Button actionListener with an actionEvent.queue() issue

The other day, I faced an issue with the programmatic taskflow navigation. At first, it seemed to be a simple task. The purpose was to click a button on a page and navigate to the next step in the bounded taskflow.

The environment is MS Windows 10, JDeveloper is 12.2.1 (Build JDEVADF_MAIN_GENERIC_151011.0031.S).

The code for the button is:
af:button text="button 1" id="b1" action="save" actionListener="#{viewScope.bean.validate}"


The code for the actionListener is:
public void validate(ActionEvent actionEvent) {
        RichButton saveButton = (RichButton) actionEvent.getComponent();
        ActionEvent action = new ActionEvent(saveButton);
        System.out.println("The listener has fired ########### ");
        action.queue();
}

When the button is clicked, the actionListener fires continuously, so the user sees that the application is hang. The Oracle Support has opened a bug 23325363 : TASKFLOW NAVIGATION USING ACTIONLISTENER IS FIRED CONTINUOUSLY, which is being worked on a priority.


Update, which works OK, but the question still remains. "save" is the name of action.

public void validate(ActionEvent actionEvent) {
//RichButton saveButton = (RichButton) actionEvent.getComponent();
//ActionEvent action = new ActionEvent(saveButton);
//action.queue();

NavigationHandler nvHndlr =
FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
nvHndlr.handleNavigation(FacesContext.getCurrentInstance(),
null,"save");
}

Monday 9 May 2016

Harry Potter and how to create MySQL fields which are auto incremented to use with ADF BC

MySQL has an auto_increment field, which can be used as a primary key. A sequence object when you think in Oracle database terms. But in the case of Oracle you can access to sequence values directly, but in the case of MySQL you don't have such a possibility.
If you want to have a field, which is auto incremented and still have the flexibility you can follow the steps below.

Create a table (counters) which stores a sequence name and last value.

CREATE TABLE `counters` (
  `counter_code` varchar(40) NOT NULL,
  `last_id` bigint(20) unsigned NOT NULL,
  `created_by` varchar(40) DEFAULT NULL,
  `creation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `last_updated_by` varchar(40) DEFAULT NULL,
  `last_updated_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`counter_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Create a procedure, which increases the sequence value and returns the value as an out parameter.
Note, that the procedure updates the counters table, this means that it has to issue a lock, which maybe the source of a bottleneck.

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `get_next_sequence_id`(in counterCode varchar(128), out lastId  bigint(20) unsigned)
BEGIN
DECLARE rowCount integer;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET rowCount=0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;
DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK;

SELECT
    COUNT(*)
INTO rowCount FROM
    counters
WHERE
    counter_code = counterCode;

if rowCount=0 then
START TRANSACTION;
INSERT INTO counters
(counter_code,last_id,created_by) VALUES(counterCode,1,'system');
COMMIT;
SET lastId =1;
else
START TRANSACTION;

UPDATE counters
SET
    last_id = (@cur_value:=last_id) + 1,
    last_updated_by = 'system'
WHERE
    counter_code = counterCode;
 
SELECT @cur_value + 1 INTO lastId;
   
   COMMIT;
end if;
END$$
DELIMITER ;

In your ADF Model Entity Object class create the following.

    @Override
    protected void create(AttributeList attributeList) {
        int nextVal = 0;
        super.create(attributeList);
        nextVal = getNextSequenceValue("NEWSEQ");
        setAttribute("ReportId", new BigDecimal(nextVal));
    }

    public int getNextSequenceValue(String sequenceNumber) {
        int nextVal = 0;
        DBTransactionImpl transaction = (DBTransactionImpl) getDBTransaction();
        CallableStatement statement = transaction.createCallableStatement("call get_next_sequence_id(?,?);", 0);
        try {
            statement.setString(1, sequenceNumber);
            statement.registerOutParameter(2, Types.INTEGER);
            statement.execute();
            nextVal = statement.getInt(2);
            statement.close();

        } catch (SQLException e) {
            throw new JboException(e);
        } finally {
            try {
                if (statement != null) {
                    statement.close();
                }
            } catch (SQLException e) {
                throw new JboException(e);
            }
        }
        return nextVal;
    }

Or you can create the same method in your AM and wire it to your attribute default value (choose "Expression") by the help of a groovy expression:adf.object.getDBTransaction().getRootApplicationModule().getNextSequenceValue("NEWSEQ")