Monday 29 August 2011

JDeveloper 10.1.3.4 on CentOS 6 x86_64

Last Thursday I formated my CentOS 5 workstation at work and reinstalled version 6 from scratch. Although we have stopped developing new application with JDeveloper 10.1.x, I still require the old jdev IDE, as existing applications need maintenance and even new features.

Making jdev 10.1.3.4 work on a 64bit Linux is discussed here , n the Darwin-It blog, to whom I own a very big thank you

Finally, I would like to offer my own piece of wisdom to whoever trying to resurrect JDeveloper 10.1 inside a new OS: Keep your paths exactly the same as the previous installation :^)

Monday 22 August 2011

SELinux and CakePHP on Fedora and CentOS

The first time I installed CakePHP, on a machine with SELinux enabled, I run into two big problems:

  1. Cake was unable to write to the application's tmp directory
  2. Cake was unable to connect tot the database, hosted on an other machine

The first thing that comes to mind, is to disable SELinux completely, and I did more than once :^). This time however, I said to myself that if so many people say SELinux is good, why not give it a try and see if we can both live peacefully on the same machine.

The first thing we need to deal with is allow access to the $APP/tmp directory. This can be accomplished by issuing :

# cd $APP
# chcon -Rv --type=httpd_user_content_rw_t tmp

Next will be to allow httpd to connect to a database hosted on a different machine than the one running the web server in case your setup use different machines for Database and web servers. This is allowed by issuing the following command again as the root user.

setsebool -P httpd_can_network_connect_db 1

For the moment my CakePHP server seems to be running fine. If any problems arise, I will update this post accordingly.

Finally a couple of links on SELinux

How to disable SELinux on Fedora, CentOS and the like

This is only a quick note, on how to disable SELinux on a system using command line tools: Open file /etc/sysconfig/selinux which should more or less be like this:

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - SELinux is fully disabled.
SELINUX=enforcing
# SELINUXTYPE= type of policy in use. Possible values are:
#       targeted - Only targeted network daemons are protected.
#       strict - Full SELinux protection.
SELINUXTYPE=targeted

Next, find the line saying: SELINUX=enforcing and replace it with SELINUX=disabled

save and reboot.

Note: Be very careful when editing this file. the other day. occidentally changed the value of SELINUXTYPE to something other than the allowed values and managed to completely prevent my 6.4 CentOS kernel from booting. (God save the live CD's ...)

Thursday 11 August 2011

CentOS: Manual IP network configuration

Just installed my first CentOS 6.0 test server. In order to save bandwidth, I downloaded the minimal installation ISO which produced a Linux system that was able to boot correctly, but provided none of the standard system-config-... tools. So in order to continue installation, I had to setup IP information for the systems network card by manually editing files. This is a summary of the steps I followed.

  1. Go to /etc/sysconfig/network-scripts/ and edit file ifcfg-eth0. Then, make sure you provide the following keys
             DEVICE=eth0
             HWADDR=00:1f:29:c3:22:16
             BOOTPROTO=static         
             NM_CONTROLLED=yes
             ONBOOT=yes
             IPADDR=10.5.0.6
             NETMASK=255.255.255.0
         
  2. Open file /etc/sysconfig//network and add information for host name and default gateway like this :
             NETWORKING=yes
             HOSTNAME=barbara.shelman.int
             GATEWAY=10.5.0.1
        
  3. The DNS servers are defined in /etc/resolv.conf. Typically the file looks like this:
             nameserver 10.5.1.1
             nameserver 10.5.1.2
         
  4. Network manager should pick up the changes immediately. In case it does not, restart the netwrok service like this :
             /etc/init.d/network restart
        

This is the minimal setup that worked for me. After I was able to set up my yum proxy and begin installation of CentOS packages, I was able to run system-config-network, which changed many of the previous entries. For example the gateway information in now stored in ifcfg-eth0, along with the DNS information. The previous setup however, is what go me started.

Friday 5 August 2011

CakePHP The Query by Example Component

After the previous post, regarding how to create and use a input QBE form, here is my simple QBE component.

To use it, paste the following code in a file named qbe.php into your APP/controllers/components directory.

<?php
/**
 * @class QbeComponent
 * Convert posted data entered in a pseudo Query by Example fashion
 * from a CakePHP Form into Model::find() acceptable conditions.
 *
 * @author: Thanassis Bakalidis
 * @version: 1.0
 */
class QbeComponent extends Object {
    // sesion keys for saving and retrieving controller data
    const CONDITIONS_SESSION_KEY = 'SRCH_COND';
    const FORM_DATA_SESSION_KEY = 'SRCH_DATA';

    // supported SQL operators
    private $SQL_OPERATORS = array(
        'IN', '<>', '>=', '<=',
        '>', '<'
    );

    var $owner;     // the controller using the component

    /**
     * @name initialize
     * The initialize method is called before the controller's
     * beforeFilter method.
     */
    function initialize(&$controller, $settings=array())
    {
        $this->owner =& $controller;
    }

    /**
     * @name: getSearchConditions()
     * Return an array to be used as search conditions in a find
     * based on the controller's current data
     * @param : string $modelName name of the model to search controller data
     * @version: 1.3
     */
    function getSearchConditions($modelName = null)
    {
        if ($modelName == null)
            return null;

        // create speciffic keys for the model andcontroller
        $sessionConditionsKey = sprintf("%s-%s-%s",
                                self::CONDITIONS_SESSION_KEY,
                                $this->owner->name,
                                $modelName
                            );
        $sessionDataKey = sprintf("%s-%s-%s",
                                self::FORM_DATA_SESSION_KEY,
                                $this->owner->name,
                                $modelName
                            );

        if (empty($this->owner->data)) {
            // attempt to read conditions from sesion
            $conditions = $this->owner->Session->check($sessionConditionsKey)
                ? $this->owner->Session->read($sessionConditionsKey)
                : array();
            $this->owner->data = $this->owner->Session->check($sessionDataKey)
                ? $this->owner->Session->read($sessionDataKey)
                : array();
        } else {
            // we have posted data. Atempt to rebuild conditons
            // array
            $conditions = array();
            foreach( $this->owner->data[$modelName] as $key => $value) {
                if (empty($value))
                    continue;

                $operator = $this->extractOperator($value);

                if (is_array($value)) {
                    // this can only be a date field

                    $month = $value['month'];
                    $day = $value['day'];
                    $year = $value['year'];

                    // We want all three variables to be numeric so we 'll check their
                    // concatenation. After all PHP numbers as just strings with digits
                    if (is_numeric($month.$day.$year) && checkdate( $month, $day, $year)) {
                        $conditionsKey ="$modelName.$key";
                        $conditionsValue = "$year-$month-$day";
                    } else
                        continue;
                } else {
                    // we have normal input, remove any leading and trailing blanks
                    $value = trim($value);                          
                    // and check the operator given
                    if ($operator === '' && !is_numeric($value)) {
                        // turn '='' to 'LIKE' for non numeric data
                        // numeric data will be treated as if they
                        // have an wquals operator
                        $operator = 'LIKE';
                        $value = str_replace('*', '%',  $value);
                        $value = str_replace('?', '.',  $value);
                    } else if ($operator === 'IN') {
                        // we need to convert the input string to an aray
                        // of the designated values
                        $operator = '';
                        $value = array_filter(explode( ' ', $value));
                    }

                    $conditionsValue = $value;
                    $conditionsKey = "$modelName.$key $operator";
                }

                // add the new condition entry
                $conditions[trim($conditionsKey)] = $conditionsValue;
            }

            // if we have some criteria, add them in the sesion
            $this->owner->Session->write($sessionConditionsKey, $conditions);
            $this->owner->Session->write($sessionDataKey, $this->owner->data);
        }

        return $conditions;
    }

    private function extractOperator(&$input)
    {
        if (is_array($input))
            return '';

        $operator = strtoupper(strtok($input, ' '));

        if (in_array($operator, $this->SQL_OPERATORS)) {
            $opLength = strlen($operator);
            $inputLength = strlen($input);
            $input = trim(substr( $input, $opLength, $inputLength - $opLength));
        } else {
            $operator = '';
        }

        return $operator;
    }
}

Next modify your AppController to use the component by adding 'Qbe' to the $components array. An example would be:

    var $components = array(
        'RequestHandler',
        'Auth',
        'Session',
        'Qbe'
    );

Now crate a query form before the results table into your index view. Copying the form from the corresponding model's create or edit pages is usually enough to get you started.

Finally, modify the corresponding controller method to use the posted data in order to create search conditions. A typical example for a model named Product would be something like that:

    function index()
    {        
        $this->Product->recursive = 0;
        $conditions = $this->Qbe->getSearchConditions($this->Product->name);
        $products = $this->paginate('Product', $conditions);

        $this->set( 'products', $products);
        $this->prepareCombos();
    }

The prepareCombos() method is a simple private function I created by copying all the find)'list', ...) commands that the cake bake script created after the add() and edit() controller methods, so that all foreign key fields have correct value ranges, when the input form gets displayed. For more information and example code, see the previous post which presents the same functionality, by adding code to the AppController.