diff --git a/src/oca/java/src/org/opennebula/client/acl/Acl.java b/src/oca/java/src/org/opennebula/client/acl/Acl.java
new file mode 100644
index 0000000000..62d2f1d560
--- /dev/null
+++ b/src/oca/java/src/org/opennebula/client/acl/Acl.java
@@ -0,0 +1,355 @@
+/*******************************************************************************
+ * Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.opennebula.client.acl;
+
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.opennebula.client.Client;
+import org.opennebula.client.OneResponse;
+import org.opennebula.client.PoolElement;
+import org.w3c.dom.Node;
+
+/**
+ * This class represents an OpenNebula ACL rule.
+ * It also offers static XML-RPC call wrappers.
+ * <br/>
+ * There is not a public constructor, because the information for an individual
+ * ACL rule cannot be retrieved from OpenNebula.
+ * <br/>
+ * Instead, Acl objects should be obtained using AclPool.getById, after the
+ * info method has been called.
+ *
+ * @see AclPool#getById
+ */
+public class Acl extends PoolElement{
+
+    private static final String METHOD_PREFIX   = "acl.";
+    private static final String ADDRULE         = METHOD_PREFIX + "addrule";
+    private static final String DELRULE         = METHOD_PREFIX + "delrule";
+
+    private static final Map<String, Long> USERS;
+    private static final Map<String, Long> RESOURCES;
+    private static final Map<String, Long> RIGHTS;
+
+    static {
+        HashMap<String, Long> tmpUsers = new HashMap<String, Long>();
+        tmpUsers.put("#", 0x0000000100000000L);
+        tmpUsers.put("@", 0x0000000200000000L);
+        tmpUsers.put("*", 0x0000000400000000L);
+
+        USERS = Collections.unmodifiableMap(tmpUsers);
+
+        HashMap<String, Long> tmpResources = new HashMap<String, Long>();
+
+        tmpResources.put("VM"       , 0x0000001000000000L);
+        tmpResources.put("HOST"     , 0x0000002000000000L);
+        tmpResources.put("NET"      , 0x0000004000000000L);
+        tmpResources.put("IMAGE"    , 0x0000008000000000L);
+        tmpResources.put("USER"     , 0x0000010000000000L);
+        tmpResources.put("TEMPLATE" , 0x0000020000000000L);
+        tmpResources.put("GROUP"    , 0x0000040000000000L);
+
+        RESOURCES = Collections.unmodifiableMap(tmpResources);
+
+        HashMap<String, Long> tmpRights = new HashMap<String, Long>();
+
+        tmpRights.put("CREATE"        , 0x1L);
+        tmpRights.put("DELETE"        , 0x2L);
+        tmpRights.put("USE"           , 0x4L);
+        tmpRights.put("MANAGE"        , 0x8L);
+        tmpRights.put("INFO"          , 0x10L);
+        tmpRights.put("INFO_POOL"     , 0x20L);
+        tmpRights.put("INFO_POOL_MINE", 0x40L);
+        tmpRights.put("INSTANTIATE"   , 0x80L);
+        tmpRights.put("CHOWN"         , 0x100L);
+
+        RIGHTS = Collections.unmodifiableMap(tmpRights);
+    }
+
+    /**
+     * @see PoolElement
+     */
+    protected Acl(Node xmlElement, Client client)
+    {
+        super(xmlElement, client);
+    }
+
+    // =================================
+    // Static XML-RPC methods
+    // =================================
+
+    /**
+     * Allocates a new ACl rule in OpenNebula
+     *
+     * @param client XML-RPC Client.
+     * @param user A string containing a hex number, e.g. 0x100000001
+     * @param resource A string containing a hex number, e.g. 0x2100000001
+     * @param rights A string containing a hex number, e.g. 0x10
+     * @return If successful the message contains the associated
+     * id generated for this rule.
+     */
+    public static OneResponse allocate(Client client, String user,
+            String resource, String rights)
+    {
+        return client.call(ADDRULE, user, resource, rights);
+    }
+
+    /**
+     * Allocates a new ACl rule in OpenNebula
+     *
+     * @param client XML-RPC Client.
+     * @param user 64b encoded user
+     * @param resource 64b encoded user
+     * @param rights 64b encoded user
+     * @return If successful the message contains the associated
+     * id generated for this rule.
+     */
+    public static OneResponse allocate(Client client, long user, long resource,
+            long rights)
+    {
+        return allocate(client,
+                Long.toHexString(user),
+                Long.toHexString(resource),
+                Long.toHexString(rights));
+    }
+
+    /**
+     * Allocates a new ACl rule in OpenNebula
+     *
+     * @param client XML-RPC Client.
+     * @param rule a rule string, e.g. "#5 HOST+VM/@12 INFO+CREATE+DELETE"
+     * @return If successful the message contains the associated
+     * id generated for this rule.
+     */
+    public static OneResponse allocate(Client client, String rule)
+    {
+        String[] components = parseRule(rule);
+        return allocate(client, components[0], components[1], components[2]);
+    }
+
+    /**
+     * Deletes an ACL rule from OpenNebula.
+     *
+     * @param client XML-RPC Client.
+     * @param id The ACL rule id.
+     * @return A encapsulated response.
+     */
+    public static OneResponse delete(Client client, int id)
+    {
+        return client.call(DELRULE, id);
+    }
+
+    // =================================
+    // Instanced object XML-RPC methods
+    // =================================
+
+    /**
+     * Deletes the ACL rule from OpenNebula.
+     *
+     * @see Acl#delete(Client, int)
+     */
+    public OneResponse delete()
+    {
+        return delete(client, id);
+    }
+
+    // =================================
+    // Helpers
+    // =================================
+
+    public long user()
+    {
+        long ret = 0;
+
+        try
+        {
+            ret = Long.parseLong( xpath("USER"), 16 );
+        }
+        catch (NumberFormatException e)
+        {}
+
+        return ret;
+    }
+
+    public long resource()
+    {
+        long ret = 0;
+
+        try
+        {
+            ret = Long.parseLong( xpath("RESOURCE"), 16 );
+        }
+        catch (NumberFormatException e)
+        {}
+
+        return ret;
+    }
+
+    public long rights()
+    {
+        long ret = 0;
+
+        try
+        {
+            ret = Long.parseLong( xpath("RIGHTS"), 16 );
+        }
+        catch (NumberFormatException e)
+        {}
+
+        return ret;
+    }
+
+    public String toString()
+    {
+        String st = xpath("STRING");
+
+        if( st == null )
+        {
+            st = "";
+        }
+
+        return st;
+    }
+
+    // =================================
+    // Rule parsing
+    // =================================
+
+    /**
+     * Parses a rule string, e.g. "#5 HOST+VM/@12 INFO+CREATE+DELETE"
+     *
+     * @param rule an ACL rule in string format
+     * @return an Array containing 3 Strings (hex 64b numbers)
+     */
+    public static String[] parseRule(String rule)
+    {
+        String [] ret = new String[3];
+
+        String [] components = rule.split(" ");
+
+        if( components.length != 3 )
+        {
+            // TODO: throw "String needs three components: User, Resource, Rights"
+            return ret;
+        }
+
+        ret[0] = parseUsers(components[0]);
+        ret[1] = parseResources(components[1]);
+        ret[2] = parseRights(components[2]);
+
+        return ret;
+    }
+
+    /**
+     * Converts a string in the form [#<id>, @<id>, *] to a hex. number
+     *
+     * @param users Users component string
+     * @return A string containing a hex number
+     */
+    private static String parseUsers(String users)
+    {
+        return Long.toHexString( calculateIds(users) );
+    }
+
+    /**
+     * Converts a resources string to a hex. number
+     *
+     * @param resources Resources component string
+     * @return A string containing a hex number
+     */
+    private static String parseResources(String resources)
+    {
+        long ret = 0;
+        String[] resourcesComponents = resources.split("/");
+
+        if( resourcesComponents.length != 2 )
+        {
+            // TODO: throw "Resource '#{resources}' malformed"
+            return "";
+        }
+
+        for( String resource : resourcesComponents[0].split("\\+") )
+        {
+            resource = resource.toUpperCase();
+
+            if( !RESOURCES.containsKey(resource) )
+            {
+                // TODO: throw "Resource '#{resource}' does not exist"
+            }
+
+            ret += RESOURCES.get(resource);
+        }
+
+        ret += calculateIds(resourcesComponents[1]);
+
+        return Long.toHexString(ret);
+    }
+
+    /**
+     * Converts a rights string to a hex. number
+     *
+     * @param rights Rights component string
+     * @return A string containing a hex number
+     */
+    private static String parseRights(String rights)
+    {
+        long ret = 0;
+
+
+        for( String right : rights.split("\\+") )
+        {
+            right = right.toUpperCase();
+
+            if( !RIGHTS.containsKey(right) )
+            {
+                // TODO throw "Right '#{right}' does not exist"
+                return "";
+            }
+
+            ret += RIGHTS.get(right);
+        }
+
+        return Long.toHexString(ret);
+    }
+
+    /**
+     * Calculates the numeric value for a String containing an individual
+     * (#id), group (@id) or all (*) ID component
+     *
+     * @param id Rule Id string
+     * @return the numeric value for the given id_str
+     */
+    private static long calculateIds(String id)
+    {
+        if( !id.matches("^([#@]\\d+|\\*)$") )
+        {
+            // TODO: throw "ID string '#{id_str}' malformed"
+            return 0;
+        }
+
+        long value = USERS.get( "" + id.charAt(0) );
+
+        if( id.charAt(0) != '*' )
+        {
+            value += Long.parseLong( id.substring(1) );
+        }
+
+        return value;
+    }
+}
diff --git a/src/oca/java/src/org/opennebula/client/acl/AclPool.java b/src/oca/java/src/org/opennebula/client/acl/AclPool.java
new file mode 100644
index 0000000000..22c6ddab1a
--- /dev/null
+++ b/src/oca/java/src/org/opennebula/client/acl/AclPool.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.opennebula.client.acl;
+
+import java.util.AbstractList;
+import java.util.Iterator;
+
+
+import org.opennebula.client.Client;
+import org.opennebula.client.OneResponse;
+import org.opennebula.client.Pool;
+import org.opennebula.client.PoolElement;
+import org.w3c.dom.Node;
+
+/**
+ * This class represents an OpenNebula ACL rule pool.
+ * It also offers static XML-RPC call wrappers.
+ */
+public class AclPool extends Pool implements Iterable<Acl>{
+
+    private static final String ELEMENT_NAME = "ACL";
+    private static final String INFO_METHOD  = "acl.info";
+
+    /**
+     * Creates a new ACL rule pool
+     * @param client XML-RPC Client.
+     */
+    public AclPool(Client client)
+    {
+        super(ELEMENT_NAME, client);
+    }
+
+    @Override
+    public PoolElement factory(Node node)
+    {
+        return new Acl(node, client);
+    }
+
+    /**
+     * Retrieves all the hosts in the pool.
+     *
+     * @param client XML-RPC Client.
+     * @return If successful the message contains the string
+     * with the information returned by OpenNebula.
+     */
+    public static OneResponse info(Client client)
+    {
+        return client.call(INFO_METHOD);
+    }
+
+    /**
+     * Loads the xml representation of the ACL rule pool.
+     *
+     * @see AclPool#info(Client)
+     */
+    public OneResponse info()
+    {
+        OneResponse response = info(client);
+        super.processInfo(response);
+        return response;
+    }
+
+    public Iterator<Acl> iterator()
+    {
+        AbstractList<Acl> ab = new AbstractList<Acl>()
+        {
+            public int size()
+            {
+                return getLength();
+            }
+
+            public Acl get(int index)
+            {
+                return (Acl) item(index);
+            }
+        };
+
+        return ab.iterator();
+    }
+
+    public Acl getById(int id)
+    {
+        return (Acl) super.getById(id);
+    }
+}
diff --git a/src/oca/java/test/AclTest.java b/src/oca/java/test/AclTest.java
new file mode 100644
index 0000000000..9b08558e64
--- /dev/null
+++ b/src/oca/java/test/AclTest.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+import static org.junit.Assert.*;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opennebula.client.Client;
+import org.opennebula.client.OneResponse;
+import org.opennebula.client.acl.*;
+
+public class AclTest
+{
+
+    private static Acl          acl;
+    private static AclPool      aclPool;
+
+    private static Client       client;
+
+    private static OneResponse  res;
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception
+    {
+        client  = new Client();
+        aclPool = new AclPool(client);
+    }
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @AfterClass
+    public static void tearDownAfterClass() throws Exception
+    {
+    }
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @Before
+    public void setUp() throws Exception
+    {
+    }
+
+    /**
+     * @throws java.lang.Exception
+     */
+    @After
+    public void tearDown() throws Exception
+    {
+        for(Acl rule : aclPool)
+        {
+            if( rule.id() != 0 )
+            {
+                rule.delete();
+            }
+        }
+    }
+
+    @Test
+    public void defaultRules()
+    {
+        res = aclPool.info();
+        assertTrue( !res.isError() );
+        
+        assertEquals(1, aclPool.getLength());
+    }
+
+    @Test
+    public void hexAllocate()
+    {
+        // Allocate rule "#1 VM+HOST/@1 INFO+CREATE"
+        res = Acl.allocate(client, "0x100000001", "0x3200000001", "0x11");
+        assertTrue( !res.isError() );
+        
+        aclPool.info();
+        acl = aclPool.getById( res.getIntMessage() );
+        
+        assertNotNull(acl);
+        
+        assertEquals(res.getIntMessage(),   acl.id());
+        assertEquals(0x100000001L,          acl.user());
+        assertEquals(0x3200000001L,         acl.resource());
+        assertEquals(0x11L,                 acl.rights());
+        assertEquals("#1 VM+HOST/@1 CREATE+INFO", acl.toString());
+    }
+    
+    @Test
+    public void numericAllocate()
+    {
+        // Allocate rule "#1 VM+HOST/@1 INFO+CREATE"
+        res = Acl.allocate(client, 0x100000001L, 214748364801L, 0x11L);
+        assertTrue( !res.isError() );
+        
+        aclPool.info();
+        acl = aclPool.getById( res.getIntMessage() );
+        
+        assertNotNull(acl);
+        
+        assertEquals(res.getIntMessage(),   acl.id());
+        assertEquals(0x100000001L,          acl.user());
+        assertEquals(0x3200000001L,         acl.resource());
+        assertEquals(0x11L,                 acl.rights());
+        assertEquals("#1 VM+HOST/@1 CREATE+INFO", acl.toString());
+    }
+    
+    @Test
+    public void ruleAllocate()
+    {
+        res = Acl.allocate(client, "@507 IMAGE/#456 CREATE");
+        assertTrue( !res.isError() );
+        
+        aclPool.info();
+        acl = aclPool.getById( res.getIntMessage() );
+        
+        assertNotNull(acl);
+
+        assertEquals(res.getIntMessage(),   acl.id());
+        assertEquals(0x2000001fbL,          acl.user());
+        assertEquals(0x81000001c8L,         acl.resource());
+        assertEquals(0x1L,                 acl.rights());
+        assertEquals("@507 IMAGE/#456 CREATE", acl.toString());
+    }
+    
+    @Test
+    public void parseRules()
+    {
+        String[] rules = { 
+            "#3 TEMPLATE/#0 INFO",
+            "#2 IMAGE/#0 INFO",
+            "@107 IMAGE+TEMPLATE/@100 INFO",
+            "* VM+IMAGE+TEMPLATE/@100 CREATE+INFO+INFO_POOL",
+            "#2345 VM+IMAGE+TEMPLATE/* CREATE+INFO+INFO_POOL+INFO_POOL_MINE+INSTANTIATE"
+        };
+
+        long[] users = {
+            0x100000003L,
+            0x100000002L,
+            0x20000006bL,
+            0x400000000L,
+            0x100000929L
+        };
+        
+        long[] resources = {
+            0x20100000000L,
+            0x8100000000L,
+            0x28200000064L,
+            0x29200000064L,
+            0x29400000000L
+        };
+        
+        long[] rights = {
+            0x10L,
+            0x10L,
+            0x10L,
+            0x31L,
+            0xf1L
+        };
+
+        for( int i = 0; i < rules.length; i++ )
+        {
+            res = Acl.allocate(client, rules[i]);
+            assertTrue( !res.isError() );
+            
+            aclPool.info();
+            acl = aclPool.getById( res.getIntMessage() );
+            
+            assertNotNull(acl);
+
+            assertEquals(res.getIntMessage(),   acl.id());
+            assertEquals(users[i],              acl.user());
+            assertEquals(resources[i],          acl.resource());
+            assertEquals(rights[i],             acl.rights());
+        }
+
+        assertTrue( true );
+    }
+    
+    @Test
+    public void delete()
+    {
+        res = Acl.allocate(client, "#1 HOST/@2 INFO_POOL");
+        assertTrue( !res.isError() );
+        
+        aclPool.info();
+        assertTrue( aclPool.getLength() == 2 );
+
+        res = Acl.delete(client, res.getIntMessage());
+        assertTrue( !res.isError() );
+        
+        aclPool.info();
+        assertTrue( aclPool.getLength() == 1 );
+    }
+
+}
diff --git a/src/oca/java/test/all_tests.sh b/src/oca/java/test/all_tests.sh
index b6dfb55c7e..27b17915c7 100755
--- a/src/oca/java/test/all_tests.sh
+++ b/src/oca/java/test/all_tests.sh
@@ -1,5 +1,21 @@
 #!/bin/bash
 
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)             #
+#                                                                            #
+# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
+# not use this file except in compliance with the License. You may obtain    #
+# a copy of the License at                                                   #
+#                                                                            #
+# http://www.apache.org/licenses/LICENSE-2.0                                 #
+#                                                                            #
+# Unless required by applicable law or agreed to in writing, software        #
+# distributed under the License is distributed on an "AS IS" BASIS,          #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
+# See the License for the specific language governing permissions and        #
+# limitations under the License.                                             #
+#--------------------------------------------------------------------------- #
+
 if [ -z $ONE_LOCATION ]; then
     echo "ONE_LOCATION not defined."
     exit -1
@@ -42,4 +58,7 @@ let RC=RC+$?
 ./test.sh GroupTest
 let RC=RC+$?
 
+./test.sh AclTest
+let RC=RC+$?
+
 exit $RC
\ No newline at end of file
diff --git a/src/oca/java/test/test.sh b/src/oca/java/test/test.sh
index 77754dd27f..1a2c3ba4fc 100755
--- a/src/oca/java/test/test.sh
+++ b/src/oca/java/test/test.sh
@@ -1,4 +1,21 @@
 #!/bin/bash
+
+# -------------------------------------------------------------------------- #
+# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org)             #
+#                                                                            #
+# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
+# not use this file except in compliance with the License. You may obtain    #
+# a copy of the License at                                                   #
+#                                                                            #
+# http://www.apache.org/licenses/LICENSE-2.0                                 #
+#                                                                            #
+# Unless required by applicable law or agreed to in writing, software        #
+# distributed under the License is distributed on an "AS IS" BASIS,          #
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
+# See the License for the specific language governing permissions and        #
+# limitations under the License.                                             #
+#--------------------------------------------------------------------------- #
+
 # Usage: test.sh <Test_name>
 # For instance: test.sh ImageTest
 
@@ -16,6 +33,9 @@ if [ -f $VAR_LOCATION/one.db ]; then
     exit -1
 fi
 
+echo "========================================================================="
+echo "Doing $1"
+echo "========================================================================="
 
 PID=$$