Failed to connect to Glassfish MysqlDatasource

Standard

The Issue

Creating a JDBC connection pool in Netbeans 8.0 on a Centos 6.5 linux distribution resulted in a class not found exception.

java.lang.classnotfoundexception com.mysql.jdbc.jdbc2.optional.mysqldatasource

This error occurs because Glassfish 4.0 bundled with Netbeans did not include the required JDBC driver.

The Solution

Download the MySQL connector driver by selecting the platform independent download. Select the compressed type of your choice (tar / zip). Extract the downloads content and look for the “mysql-connector-java-5.x.x-bin.jar” file. This is the file that Glassfish needs to properly load the MySQL datasource.

Place the jar file in the the following location

\PATH\TO\GLASHFISH\INSTALL\FOLDER\glassfish4.X.X\glassfish\lib

After placing the jar file in the Glassfish lib folder restart the server. This should fix the class not found exception.

Couchbase Datasource

Standard

I ran into a problem where I needed to utilize a NoSQL database. Since CakePHP is more fit for relational style database (MYSQL) I had to create a custom datasource. The following datasource allows models to have basic functionality of Couchbase Server.

Example Usage:

$keyName = "Jackson";
$cache = $this->YourModel->Get(array($keyName));
if (!$cache) {
   $data = array('Firstname' => 'Jessie',
                 'Lastname' => 'Jackson');
   $this->YourModel->Assign(array($keyName), json_encode($data));
}

Setup / Configuration:

To use the couchbaseSource you must specify it in your model. Do so by adding the following.
YourModel.php

public $useDbConfig = ‘bucketCB';

You can also programmatically change datasouces / database on the fly. For example, sometimes I want to use my default MYSQL datasource. This can be accomplished like so:

if($useNOSQL) {
   $this->Model->useDbConfig = 'bucketCB';
}else {
   $this->Model->useDbConfig = 'default'; // MYSQL
}

To use be able to use this datasource it must be added to cakePHP list of available datasources.
Database.php

public $bucketCB = array(
    'datasource' => 'CouchbaseSource',
    'username' => ‘bucketUsername,
    'password' => ‘bucketPassword’,
    'bucket' => ‘bucketName,
    'prefix' => ‘p’, // A _ is automatically prepended
    'expiry' => '1814400', // 3 Weeks
    'autoConnect' => true,
    'database' => NULL,
    'persistent' => false
);

app/Model/Datasource/CouchbaseSource.php

/**
 * Couchbase Datasource class
 * @Author Brandon Klimek
 * 
 */
class CouchbaseSource extends DataSource {

    /**
     * Description of datasource
     *
     * @var string
     */
    public $description = 'Couchbase DataSource';

    /**
     * Holds the object for the connected database
     *
     * @var object
     */
    public $conObject = NULL;

    /**
     * Holds the configuration settings that are passed in
     *
     * @var array
     */
    public $config = NULL;

    /**
     * The prefix of the couchbase keys
     *
     * @var string
     */
    public $prefix = NULL;

    /**
     * CouchDBSource Constructor
     *
     * @param array $config The configuration for the Datasource
     *
     * @return void
     * @link http://api.cakephp.org/class/data-source#method-DataSource__construct
     */
    public function __construct($config = array()) {

        // If no configuration is set we use the default
        $this->config = $config;

        // Setup the cache string that is used when building the string
        $this->prefix = (isset($this->config['prefix']) ? $this->config['prefix'] . "_" : "");

        if ($this->config['autoConnect']) {
            $this->connect();
        }
    }

    /**
     * Connect to the Datasource
     *
     * @return obj
     * @throws InternalErrorException
     */
    public function connect() {
        if ($this->conObject !== true) {
            try {
                $this->conObject = new Couchbase("127.0.0.1:8091", $this->config['username'], $this->config['password'], $this->config['bucket'], $this->config['persistent']);
            } catch (CouchbaseException $e) {
                throw new InternalErrorException(array('class' => $e->getMessage()));
            }
        }
        return $this->conObject;
    }

    /**
     * Handle queries to couchbase
     *
     * @param unknown_type $method
     * @param array() $param
     * @return array or false
     */
    public function query($method, $params) {

        // If not connected... reconnect!
        if ($this->conObject === NULL) {
            $this->connect();
        }

        $apiMethod = $this->__methodToClass($method);
        if (!method_exists($this, $apiMethod)) {
            throw new NotFoundException("Class '{$apiMethod}' was not found");
        } else {
            return call_user_func_array(array($this, $apiMethod), $params);
        }
    }

    /**
     * Translate method to className
     *
     * @param $method
     * @return string
     */
    private function __methodToClass($method) {
        return 'CB' . strtolower(Inflector::camelize($method));
    }

    /**
     * describe() tells the model your schema for ``Model::save()``.
     *
     * You may want a different schema for each model but still use a single
     * datasource. If this is your case then set a ``schema`` property on your
     * models and simply return ``$Model->schema`` here instead.
     */
    public function describe(&$Model) {
        return $this->description;
    }

    /////////////////////////////////////////////////
    // Query Methods
    /////////////////////////////////////////////////

    /**
     * Add a value with the specified key that does not already exist. Will fail if the key/value pair already exist.
     *
     * @return Contains the document ID or false if the operation failed
     */
    public function CBadd($key = NULL, $value = NULL, $expiry = NULL, $persisto = NULL, $replicateto = NULL) {
        return $this->conObject->add($key, $value, $expiry, $persisto, $replicateto);
    }

    /**
     * Append a value to an existing key
     *
     * @return scalar ( Binary object )
     */
    public function CBappend($key = NULL, $value = NULL, $expiry = NULL, $persisto = NULL, $replicateto = NULL) {
        return $this->conObject->append($key, $value, $expiry, $persisto, $replicateto);
    }

    /**
     * Compare and set a value providing the supplied CAS key matches
     *
     * @return scalar ( Binary object )
     */
    public function CBcas($casimoqie = NULL, $key = NULL, $value = NULL, $expiry = NULL) {
        return $this->conObject->cas($casimoqie, $key, $value, $expiry);
    }

    /**
     * Decrement the value of an existing numeric key. The Couchbase Server stores numbers as unsigned values. Therefore the lowest you can decrement is to zero.
     *
     * @return scalar ( Binary object )
     */
    public function CBdecrement($key = NULL, $offset = NULL) {
        return $this->conObject->decrement($key, $offset);
    }

    /**
     * Delete a key/value
     *
     * @return scalar ( Binary object )
     */
    public function CBdelete($key = NULL, $offset = NULL) {
        $this->conObject->delete($key, $offset);
    }

    /**
     * Wait until the durability of a document has been reached
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBkeyDurability($key = NULL, $casunique = NULL) {
        return $this->conObject->keyDurability($key, $casunique);
    }

    /**
     * Wait until the durability of a document has been reached
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBflush() {
        return $this->conObject->flush();
    }

    /**
     * Get a value and update the expiration time for a given key
     *
     * @return obj
     */
    public function CBgetAndTouch($key = NULL, $expiry = NULL) {
        return $this->conObject->getAndTouch($key, $expiry);
    }

    /**
     * Get a value and update the expiration time for a given key
     *
     * @return obj
     */
    public function CBgetAndTouchMulti($key = NULL, $expiry = NULL) {
        return $this->conObject->getAndTouchMult($key, $expiry);
    }

    /**
     * Fetch the next delayed result set document
     *
     * @return array ( Result list )
     */
    public function CBfetch($key = NULL, $keyn = NULL) {
        return $this->conObject->fetch($key, $keyn);
    }

    /**
     * Fetch all the delayed result set documents
     *
     * @return array ( Result list )
     */
    public function CBfetchAll($key = NULL, $keyn = NULL) {
        return $this->conObject->fetchAll($key, $keyn);
    }

    /**
     * Get one or more key values
     *
     * @return scalar ( Binary object )
     */
    public function CBget($key = NULL, $callback = NULL, $casunique = NULL) {

        if (is_array($key)) {
            $key = $this->buildCacheString($key);
        }
        return $this->conObject->get($key, $callback, $casunique);
    }

    /**
     * Get one or more key values
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBgetDelayed($keyn = NULL, $with_cas = NULL, $callback = NULL) {
        return $this->conObject->getDelayed($keyn, $with_cas, $callback);
    }

    /**
     * Get one or more key values
     *
     * @return array ( Array of documents )
     */
    public function CBgetMulti($keycollection = NULL, $casarray = NULL) {
        return $this->conObject->getMulti($keycollection, $casarray);
    }

    /**
     * Returns the version of the client library
     *
     * @return scalar ( Binary object )
     */
    public function CBgetClientVersion() {
        return $this->conObject->getClientVersion();
    }

    /**
     * Get the value for a key, lock the key from changes
     *
     * @return (none)
     */
    public function CBgetAndLock($key = NULL, $casarray = NULL, $getlexpiry = NULL) {
        return $this->conObject->getAndLock($key, $casarray, $getlexpiry);
    }

    /**
     * Get the value for a key, lock the key from changes
     *
     * @return (none)
     */
    public function CBgetAndLockMulti($keycollection = NULL, $casarray = NULL, $getlexpiry = NULL) {
        return $this->conObject->getAndLockMulti($keycollection, $casarray, $getlexpiry);
    }

    /**
     * Returns the number of replicas for the configured bucket
     *
     * @return scalar ( Number of replicas )
     */
    public function CBgetNumReplicas() {
        return $this->conObject->getNumReplicas();
    }

    /**
     * Retrieve an option
     *
     * @return mixed ( Different possible types )
     */
    public function CBgetOption($option) {
        return $this->conObject->getOption($option);
    }

    /**
     * Returns the versions of all servers in the server pool
     *
     * @return array ( List of things )
     */
    public function CBgetVersion() {
        return $this->conObject->getVersion();
    }

    /**
     * Execute a view request
     *
     * @return (none)
     */
    public function CBview($ddocname = NULL, $viewname = NULL, $viewoptions = array()) {
        return $this->conObject->view($ddocname, $viewname, $viewoptions);
    }

    /**
     * Generate a view request, but do not execute the query
     *
     * @return (none)
     */
    public function CBviewGenQuery($ddocname = NULL, $viewname = NULL, $viewoptions = NULL) {
        return $this->conObject->viewGenQuery($ddocname, $viewname, $viewoptions);
    }

    /**
     * Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if 
     * you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric 
     * result. If a key does not exist, this method will initialize it with the zero or a specified value.
     *
     * @return scalar ( Binary object )
     */
    public function CBincrement($key = NULL, $offset = NULL, $create = NULL, $expiry = NULL, $initial = NULL) {
        return $this->conObject->increment($key, $offset, $create, $expiry, $initial);
    }

    /**
     * Get the durability of a document
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBobserve($key = NULL, $casunique = NULL, $observeddetails = NULL) {
        return $this->conObject->observe($key, $casunique, $observeddetails);
    }

    /**
     * Get the durability of a document
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBobserveMulti($keycollection = NULL, $observeddetails = NULL) {
        return $this->conObject->observeMulti($keycollection, $observeddetails);
    }

    /**
     * Prepend a value to an existing key
     *
     * @return scalar ( Binary object )
     */
    public function CBprepend($key = NULL, $value = NULL, $expiry = NULL, $casunique = NULL, $persistto = NULL, $replicateto = NULL) {
        return $this->conObject->prepend($key, $value, $expiry, $casunique, $persistto, $replicateto);
    }

    /**
     * Update an existing key with a new value
     *
     * @return scalar ( Binary object )
     */
    public function CBreplace($key = NULL, $value = NULL, $expiry = NULL, $casunique = NULL, $persistto = NULL, $replicateto = NULL) {
        return $this->conObject->replace($key, $value, $expiry, $casunique, $persistto, $replicateto);
    }

    /**
     * Store a value using the specified key, whether the key already exists or not. Will overwrite a value if the given key/value already exists.
     *
     * @return scalar ( Binary object )
     */
    public function CBassign($key = NULL, $value = NULL, $expiry = NULL, $casunique = NULL, $persistto = NULL, $replicateto = NULL) {

        if (is_array($key)) {
            $key = $this->buildCacheString($key);
        }

        $time = (($expiry == NULL) ? $this->config['expiry'] : $expiry);

        try {
            $this->conObject->set($key, $value, $time, $casunique, $persistto, $replicateto);
        } catch (Exception $e) {
            return false;
        }
        return true;
    }

    /**
     * Set multiple key/value items at once
     *
     * @return scalar ( Binary object )
     */
    public function CBassignMulti($kvarray = NULL, $expiry = NULL) {
        return $this->conObject->setMulti($kvarray, $expiry);
    }

    /**
     * Specify an option
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBsetOption($option = NULL, $mixed = NULL) {
        return $this->conObject->setOption($option, $mixed);
    }

    /**
     * Get the database statistics
     *
     * @return array ( List of things )
     */
    public function CBgetStats() {
        return $this->conObject->getStats();
    }

    /**
     * Update the expiry time of an item
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBtouch($key = NULL, $expiry = NULL) {
        return $this->conObject->touch($key, $expiry);
    }

    /**
     * Change the expiration time for multiple documents
     *
     * @return boolean ( Boolean (true/false) )
     */
    public function CBtouchMulti($keyarray = NULL, $expiry = NULL) {
        return $this->conObject->touchMulti($keyarray, $expiry);
    }

    /**
     * Private buildCacheString
     *
     * Takes in a array and then splits it into a string and underscores
     *
     * @param array resetSplit
     * @return string
     */
    private function buildCacheString($restSplit = array()) {

        $count = count($restSplit);
        $string = "";
        foreach ($restSplit as $key => $method) {
            $string .= Inflector::slug($method);
            if ($count - 1 != $key) {
                $string .= "_";
            }
        }
        return strtolower($this->prefix . $string);
    }

}