Building Joomla! extensions with Phing

This script is intended to be used if you are in a situation where you develop your extensions inside a joomla tree but store them in a repository or folder outside the tree. The script provides functionality to copy the extension by name out of the joomla tree.

Configuration

Rename build.properties.dist to build.properties and set the src.dir variable to the Joomla! path. For example

src.dir=/var/www/joomla

This is where the script will look for the components you are trying to build.

Naming conventions

The script uses the extension prefix to determine the extension type, so you have to use the following prefixes to the extension=VALUE

  • component : “com_”
  • module : “mod_”
  • template : “tpl_”
  • plugin: “plg_GROUP_”

Administrator modules and templates must use the following prefixes

  • module: “mod_admin_”
  • template: “tpl_admin_”

Language files

When using this script, the language files for an extension needs to be stored within the folder of the extension itself and not in the global language folder.

Usage examples

Building an extension from the joomla source tree

phing -Dextension=com_content build

Creating a package

Once you have built an extension you can create an installable package from the build using the following command.

phing -Dextension=com_content

This will create a package file “com_content_DATE.zip

If you also wish to add a version number you can use the following procedure

phing -Dextension=com_content -Dversion=2.5

Download latest version
or…
Take a peek at the source

Loading the Joomla! Platform in an external script

If you are looking to execute an external PHP script, and still have access to the functionality of the platform and your site, you can do something like this in order to load the platform.

<?php define('_JEXEC', 1);
define('DS', DIRECTORY_SEPARATOR);
 
if (file_exists(dirname(__FILE__) . '/defines.php')) {
    include_once dirname(__FILE__) . '/defines.php';
}
 
if (!defined('_JDEFINES')) {
    define('JPATH_BASE', dirname(__FILE__));
    require_once JPATH_BASE.'/includes/defines.php';
}
 
require_once JPATH_BASE.'/includes/framework.php';
 
/* Your code here */

If we take a closer look at the code, the first if construct will check if there exists a defines.php file in the directory of your external PHP script, and use if in case it does. If that file is not found, it will look in the includes subdirectory for defines.php. After the defines are included, the platform is loaded. There is really not much more to it, now you will be able to use the Joomla! platform like you would inside Jooml!. For example by instantiating JDatabase through $database = JFactory::getDBO(); or accessing the request through JRequest.

Removing the components administrator menu

So, your shiny new frontend component is all written and works flawlessly without any kind of bugs whatsoever and now you would like to remove the component menu item in the administrator Components menu. Why you say ? Of course because your shiny new component is a frontend-only component and you do not want to implement a dummy backend interface just because it is cool.

So here is how you do it, if you need to know how to create an installer script for your component, please refer to the official Joomla! MVC Component tutorial.

class Com_HelloworldInstallerScript {
    function postflight($type, $parent){
        if ($type == 'install' || $type == 'update') {
            $db = JFactory::getDBO();
            $query = $db->getQuery(true);
            $query->delete('#__menu');
            $id = JComponentHelper::getComponent('com_helloworld')->id;
            $query->where('component_id = '.$id);
            $query->where('client_id = 1');
            $db->setQuery($query);
            $db->query();
        }   
    }   
}

Note that during uninstall of a component which has had its menu entry removing in this manner, there will be a warning/error in versions 1.7.0 and older. The component will still uninstall like it should so do not worry if you see this error.

Atomic locking in Intel® 64 and IA-32 architectures

The Intel® 64 and IA-32 architecture guarantees atomicity if one of the following conditions are met

  • Reading or writing a byte
  • Reading or writing a word aligned on a 16-bit boundary
  • Reading or writing a double word aligned on a 32-bit boundary
So what does this mean ? It means that if we are clever about it, we can implement a simple lock using atomic reading and writing of a single byte.

The following function will use the XCHG instruction to swap two registers atomically, so all we have to do is give it the address to our locking variable and check the return value. If the value returned from the function is LOCKED it means that the thread was unable to acquire the lock. The beauty about this instruction is that if it is used to reference one general purpose register and a memory address, the processor bus locking protocol will be invoked causing the operation to become atomic.

The inline assembly statement might look daunting at first, but it is not really that complicated.

Per definition the structure of such an inline extended assembly statement is like this:

       asm ( assembler template 
           : output operands
           : input operands
           : list of clobbered registers
           );

The use of the operands is optional, and we do not use and clobbered registers in this statement, we trust the compiler to figure that out.

As you can see, we provide one output operand and two input operands. The output operand is the variable where we will store the previous value of the lock, and the variable that the caller uses to check if the lock was successfully acquired.

In input and output operands we can specify various constraints:

  • As you look at the “0″(value) operand, the “0″ is the constraint telling it that the value of this input operand is ONLY allowed to be stored in the 0th output variable, which is the output variable value.
  • The “a” constraint of address specifies that the value should be stored in the EAX register.
  • The “=b” constraint of the output operand specifies that this value should be read from EBX, and the operand is write-only.
#define LOCKED   = 1
#define UNLOCKED = 0
 
static int test_and_set(int *address)
{
	int value = LOCKED;
	asm volatile ("xchg (%%eax), %%ebx"
		      :"=b" (value)
		      :"0"(value), "a"(address));
	return value;
}

So there we have it, essentially this says “Take the memory address given in the address variable and store the value given in the value variable in it, while putting the previous content of that memory address into the value variable when done.”

When the caller checks the returned value, if the value is LOCKED it will know that the lock was already taken, and if the value is UNLOCKED it will know that the previous value was unlocked, thus the locked has now been taken.

Fort l’Ecluse & Climbing at Leaz

So we went to visit Fort l’Ecluse which was at the time hosting an exhibition from CERN featuring a lot of nice pictures from the various detectors and also some very nice holographic imagery that I managed to get a couple of good shots of.

There is also a very nice via ferrata climbing route there which I hope to be able to do in the near future.

After spending the day walking around in the old castle (yes, plenty of stairs…) we went for a nice climbing trip at Leaz, which is a small village at the foot of the Jura mountains.

2011-07 15-39-11_0002.jpg2011-07 15-39-20_0003.jpg2011-07 15-21-28_0001.jpg2011-07 15-40-58_0004.jpg2011-07 15-55-59_0005.jpg2011-07 15-57-14_0006.jpg2011-07 15-58-02_0007.jpg2011-07 16-13-42_0009.jpg2011-07 16-17-35_0010.jpg2011-07 17-36-17_0011.jpg2011-07 17-37-49_0012.jpg2011-07 16-11-56_0008.jpg2011-07 17-43-45_0014.jpg2011-07 17-46-20_0015.jpg2011-07 17-40-18_0013.jpg2011-07 18-06-27_0017.jpg2011-07 18-08-22_0018.jpg2011-07 17-51-30_0016.jpg

IBM Active Protection System


Playing around on my thinkpad, I discovered that the HDAPS system can be used to do more than just protect your hard drive in case of a fall.

The following application displays a 3D model of a cube representing the monitored laptop, a server running on that laptop is sending real-time updates using information it gets from the IBM Hard Drive Active Protection System (HDAPS). This allows a remote client to monitor the movement of the laptop. The application itself is not very impressive, but I included a screenshot anyway.

Hooking up to the input subsystem through JNI

Making raw input data available to Java3D through the use of JNI. The device is a 3dConnexion Space Navigator, it registers itself as an event device through the input subsystem.

Our Java class

class ReadFile {
    native static int[] readEvent();
 
    //Load the library
    static {
        System.loadLibrary("nativelib");
    }
 
    public static void main(String args[]) {
        while(true){
            int event[] = new ReadEvents().readEvent();
            System.out.print("Event: ("+event.length+" bytes): ");
            for(int b: event)
                System.out.print(new Integer(b) + " ");
                System.out.println();
        }
    }
}

The Makefile used to build the shared library

CC=gcc
JC=javac
JH=javah
 
CFLAGS= -shared -Wall
INCLUDEPATH= \
     -I/usr/lib/jvm/java-6-sun-1.6.0.16/include/ \
     -I/usr/lib/jvm/java-6-sun-1.6.0.16/include/linux
 
all:
$(JC) ReadEvents.java
$(JH) ReadEvents
$(CC) $(CFLAGS) -o libnativelib.so $(INCLUDEPATH) events.c

This is really all the C code we need to pass the axes array

#define EVENTNODE "/dev/input/event6"
 
int axes[6] = {0,0,0,0,0,0};
int btns[2] = {0,0};
int fd = 0;
 
JNIEXPORT jintArray JNICALL Java_ReadEvents_readEvent(
    JNIEnv* env, jclass cl)
{
        if(fd == 0){
                fd = open(EVENTNODE , O_RDONLY);
        }
        struct input_event ev;
        read(fd, &amp;ev, sizeof(struct input_event));
 
        switch (ev.type){
                        case EV_KEY:
                                btns[ev.code] = ev.value;
                                break;
                        case EV_REL:
                                axes[ev.code] = ev.value;
                                break;
        }
        jintArray jb;
        jb = (*env)-&gt;NewIntArray(env, 6);
        (*env)-&gt;SetIntArrayRegion(env, jb, 0, 6, (jint *)axes);
        return (jb);
}