terça-feira, 29 de abril de 2014

How to Ramp-up threads in a specific sampler using JMeter

Apache JMeter has a Ramp-up configuration in Thread Group component.



But, what should you do if you have to ramp-up in a specific sampler?

One of the approaches I like to use is including a Javascript function in a Constant Timer.

The expression ${__javaScript(${__threadNum()}*1000)} will delay every thread by 1 second (1000 milliseconds).


Be aware that when executing this script in a distributed environment, the function ${__threadNum()} will return the same consecutive numbers (1, 2, 3, ...) for each JMeter Slave/Server used. That's because there is a "Thread 1" (or "Thread 2", "Thread 3", and so on) for each JMeter Slave/Server.

In this example I added a Synchronizing Timer and a View Results Tree to better understand the effects of this approach.



JMeter script (version 2.11) used in this post can be found here.

domingo, 17 de junho de 2012

How to dynamically increase/decrease load using JMeter

Recently, in JMeter's Users Mailing List, a member asked if is possible to make a dynamic threading model using JMeter and the answer to this question instigated me.

So, is it possible to setup a dynamic threading model using JMeter?

For this post I'm using JMeter 2.7, but it would work on earlier versions too.

Part 1 - Setting up the magic

 - Create a file and, in its content, write the number of initial threads to be executed. Example: If I want to increase the load 10 by 10 and start the test only with 5, I'll put 5 in the file content;
- Publish this file in a way it can be accessed by an HTTP Request Sampler.

Obs.: you could use any sampler you want, since it can access the file and the response can be extracted to a variable.

Part 2 - Setting up the test

* the ordered list is similar to the JMeter's script tree model.

1. Adding variables to Test Plan

    - maxThreads: the maximum number of threads you will run on the test

    Set maxThreads to 11, just for this test.


2. Adding a Thread Group

    - Number of threads: ${maxThreads}
    - Rampup: 0 (see details bellow)
    - Forever: checked (on earlier versions set Loop count to -1)




    If you want to use a Ramp-up interval, this will affect the start time of the last thread. Because of that the expressions used in If Controller component's conditions shown in this post have to be changed.

3. Adding the first If Controller

    - condition: ${__threadNum()} === ${maxThreads}

    What is it for?
    We'll use only one thread as a load controller.



    On a distributed testing you can use a different condition to run at only one JMeter server instance. I'll consider adding ${__machineName()} is suffice.

    - condition: (${__threadNum() === ${maxThreads}) && ("${__machineName()}" === "jmeter-server-1")

3.1. Adding an HTTP Request Sampler

    This sampler will access the file created and published at Part 1.



3.1.1. Adding a Regular Expression Extractor

    This post-processor will set a thread variable with the content of the response.

    Regular Expression: (.*)
    Model: $1$
    Match to number: 1
    Reference name: threads



    Regular Expression Post-Processor creates a thread variable that, by default, is not shared with others.
    We'll, then, add another component to share its value.

3.1.2. Adding a BSF Post-Processor

    This one will set a property used along by other threads.

    Language: javascript
    Script: var threads = vars.get("threads");
               props.put("currentThreads", threads);



3.2. (optional) Adding a Debug Sampler

    JMeter properties: True
    JMeter variables: True
    System properties: False



4. Adding the second If Controller

    - condition: ${__threadNum()} < ${maxThreads}

    This controller is needed only if you want to separate a thread specifically to item 3 of this post. If you prefer to reuse the thread to also execute the samplers, ignore this  controller and use item 4.1 as a substitute.



4.1. Adding the third If Controller

    - condition: ${__threadNum()} <= ${__P("currentThreads",0)}

    This controller condition will execute only the threads accordingly to the value defined in the file content published at "Part 1".



4.1.1. Here goes the test it self

    Bellow the third If Controller tree node will be added the samplers used by the real test scenario.

    Just for the proof of concept, add an HTTP Request Sampler and change its label to "__threadNum() = ${__threadNum()} & currentThreads = ${__P(currentThreads,0)}"



5. Adding a Results Tree Listener

    With this component we'll see what happens when the file, created and published at "Part 1", has its content updated.

6. Time to test

    My test setup:

        - threads.txt content: 0
        - maxThreads: 11
        - currentThreads 0
        - inside each sampler I added a Constant Timer with 1 second delay.

    Start the test. Look at Results Tree Listener. As we can see, only the sampler inside the first If Controller is executed.



    If we change the content of threads.txt to, let's say, 4, this will affect the test when next iteration starts.



Conclusion

    Yes. It's possible to achieve a dynamically controlled threading model. Although this can, hardly, be useful to short time tests, it makes more sense to long running threads, either using infinite Loop count, Runtime Controller, While Controller or other components or techniques. This is one way to do it and I believe that has some more.

    As a JMeter fan, I would like to see this feature added to JMeter in an easier way. As a developer, I have to learn more from JMeter code and contribute to improve this awesome tool.

** the script file can be downloaded here.

quinta-feira, 27 de outubro de 2011

Unable to process annotations for url ... error in opening zip file

For those who are suffering from errors such as
"Unable to process annotations for url, vfs:/D:/servers/jboss-6.0.0.Final/server/default/deploy/ebreez.war/WEB-INF/lib/richfaces-core-impl-4.0.0.Final.jar/META-INF/faces-config.xml. Reason: java.util.zip.ZipException: error in opening zip file"
or
"Unable to process annotations for url, vfs:/D:/servers/jboss-6.0.0.Final/server/default/deploy/ebreez.war/WEB-INF/lib/primefaces-3.0.0.M3.jar/META-INF/faces-config.xml. Reason: java.util.zip.ZipException: error in opening zip file"
there's a solution. Add the class described below into your source code (feel free to modify package and/or classe name) and create a text file, named com.sun.faces.spi.annotationprovider, inside java_source_folder/META-INF/services, containing the full qualified class name of this class.

package org.jboss.as.scanner; // Modify package name as your wish

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletContext;

import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;

import com.sun.faces.config.AnnotationScanner;
import com.sun.faces.util.FacesLogger;

public class JBossJavaClassScanningAnnotationScanner extends
  AnnotationScanner {

    private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();

    // Matcher.group(1) == the URL to the JAR file itself.
    // Matcher.group(2) == the name of the JAR.
    private static final Pattern JAR_PATTERN = Pattern.compile("(.*/(\\S*\\.jar)).*");

    private static final String WEB_INF_CLASSES = "/WEB-INF/classes/";

    private ClassFile classFileScanner;

    // ------------------------------------------------------------ Constructors


    /**
     * Creates a new <code>AnnotationScanner</code> instance.
     *
     * @param sc the <code>ServletContext</code> for the application to be
     *  scanned
     */
    public JBossJavaClassScanningAnnotationScanner(ServletContext sc) {
        super(sc);
        classFileScanner = new ClassFile();
    }


    // ---------------------------------------------------------- Public Methods


    /**
     * @return a <code>Map</code> of classes mapped to a specific annotation type.
     *  If no annotations are present, or the application is considered
     * <code>metadata-complete</code> <code>null</code> will be returned.
     */
    @Override
    public Map<Class<? extends Annotation>,Set<Class<?>>> getAnnotatedClasses(Set<URI> uris) {

        Set<String> classList = new HashSet<String>();

        processWebInfClasses(sc, classList);
        processClasspath(uris, classList);
        processScripts(classList);

        return processClassList(classList);
    }


    // --------------------------------------------------------- Private Methods

    /**
     * Scans for annotations on classes within JAR files on the classpath.
     *
     * @param uris to a faces-config documents that allow us to refer to
     *  unique jar files on the classpath
     * @param classList the <code>Set</code> to which annotated classes
     *  will be added
     */
    private void processClasspath(Set<URI> uris, Set<String> classList) {

        for (URI uri : uris) {
         if("vfs".equals(uri.getScheme())) {
                try {
                   VirtualFile virtualFile = VFS.getChild(uri);
                   VirtualFile metaInf = virtualFile.getParent();
                   VirtualFile jarFile = metaInf.getParent();
                   VirtualFile jarContainer = jarFile.getParent();
                   uri =
                      new File(jarContainer.getPhysicalFile(),
                         jarFile.getName() + File.pathSeparatorChar +
                         metaInf.getName() + File.pathSeparatorChar + virtualFile.getName()
                      ).toURI();
                } catch(Exception e) {
                }
             }
            try {
                Matcher m = JAR_PATTERN.matcher(uri.toString());
                if (m.matches()) {
                    String jarName = m.group(2);
                    if (!processJar(jarName)) {
                        continue;
                    }
                    StringBuilder sb = new StringBuilder(32);
                    String us = m.group(1);
                    if (us.startsWith("vfs:")) {
                     sb.append(us);
                    } else if (!us.startsWith("jar:")) {
                        sb.append("jar:");
                    }
                    if (us.startsWith("zip:")) {
                     sb.append("file:").append(us.substring(4));
                    } else if (us.startsWith("bundle:")) {
                     sb.append("file:").append(us.substring(7));
                    } else {
                     sb.append(us);
                    }
                    sb.append("!/");
                    URL u = new URL(sb.toString());
                    URLConnection urlConn = u.openConnection();
                    if (urlConn instanceof JarURLConnection) {
                     JarFile jarFile =
                      ((JarURLConnection) u.openConnection()).getJarFile();
                     processJarEntries(jarFile,
                       ((getClasspathPackages() != null)
                         ? getClasspathPackages().get(jarName)
                           : null),
                           classList);
                    }
                } else {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.fine("Unable to match URL to a jar file: " + uri
                              .toString());
                    }
                }
            } catch (Exception e) {
                if (LOGGER.isLoggable(Level.SEVERE)) {
                    LOGGER.log(Level.SEVERE,
                               "Unable to process annotations for url, {0}.  Reason: "
                               + e.toString(),
                               new Object[]{uri});
                    LOGGER.log(Level.SEVERE, "", e);
                }
            }
        }

    }


    /**
     * Called by {@link ConstantPoolInfo} when processing the bytes of the
     * class file.
     *
     * @param value the String value as provided from {@link ConstantPoolInfo}
     * @return <code>true</code> if the value is one of the known
     *  Faces annotations, otherwise <code>false</code>
     */
    private static boolean isAnnotation(String value) {

        return FACES_ANNOTATIONS.contains(value);

    }


    /**
     * Process the entries in the provided <code>JarFile</code> looking for
     * class files that may be annotated with any of the Faces configuration
     * annotations.
     *
     * @param jarFile the JAR to process
     * @param allowedPackages the packages that should be scanned within the jar
     * @param classList the <code>Set</code> to which annotated classes
     *  will be added
     */
    private void processJarEntries(JarFile jarFile, String[] allowedPackages, Set<String> classList) {

        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.log(Level.FINE,
                        "Scanning JAR {0} for annotations...",
                        jarFile.getName());
        }

        for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
            JarEntry entry = entries.nextElement();
            if (entry.isDirectory()) {
                continue;
            }

            String name = entry.getName();
            if (name.startsWith("META-INF")) {
                continue;
            }

            if (name.endsWith(".class")) {
                String cname = convertToClassName(name);
                if (!processClass(cname, allowedPackages)) {
                    continue;
                }
                ReadableByteChannel channel = null;
                try {
                    channel = Channels.newChannel(jarFile.getInputStream(entry));
                    if (classFileScanner.containsAnnotation(channel)) {
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.log(Level.FINE,
                                       "[JAR] Found annotated Class: {0}",
                                       cname);
                        }
                        classList.add(cname);
                    }
                } catch (IOException e) {
                    if (LOGGER.isLoggable(Level.SEVERE)) {
                        LOGGER.log(Level.SEVERE,
                                   "Unexpected exception scanning JAR {0} for annotations",
                                   jarFile.getName());
                        LOGGER.log(Level.SEVERE,
                                   e.toString(),
                                   e);
                    }
                } finally {
                    if (channel != null) {
                        try {
                            channel.close();
                        } catch (IOException ignored) {
                            if (LOGGER.isLoggable(Level.FINE)) {
                                LOGGER.log(Level.FINE,
                                           ignored.toString(),
                                           ignored);
                            }
                        }
                    }
                }
            }
        }

    }


    /**
     * Scan <code>WEB-INF/classes</code> for classes that may be annotated
     * with any of the Faces configuration annotations.
     *
     * @param sc the <code>ServletContext</code> for the application being
     *  scanned
     * @param classList the <code>Set</code> to which annotated classes
     *  will be added
     */
    private void processWebInfClasses(ServletContext sc, Set<String> classList) {

        processWebInfClasses(sc, WEB_INF_CLASSES, classList);

    }


    /**
     * Scan <code>WEB-INF/classes</code> for classes that may be annotated
     * with any of the Faces configuration annotations.
     *
     * @param sc the <code>ServletContext</code> for the application being
     *  scanned
     * @param path the path to start the scan from
     * @param classList the <code>Set</code> to which annotated classes
     *  will be added
     */
    private void processWebInfClasses(ServletContext sc,
                                      String path,
                                      Set<String> classList) {

        //noinspection unchecked
        Set<String> paths = sc.getResourcePaths(path);
        processWebInfClasses(sc, paths, classList);

    }


    /**
     * Scan <code>WEB-INF/classes</code> for classes that may be annotated
     * with any of the Faces configuration annotations.
     *
     * @param sc the <code>ServletContext</code> for the application being
     *  scanned
     * @param paths a set of paths to process
     * @param classList the <code>Set</code> to which annotated classes
     *  will be added
     */
    private void processWebInfClasses(ServletContext sc,
                                      Set<String> paths,
                                      Set<String> classList) {

        if (paths != null && !paths.isEmpty()) {
            for (String pathElement : paths) {
                if (pathElement.endsWith("/")) {
                    processWebInfClasses(sc, pathElement, classList);
                } else {
                    if (pathElement.endsWith(".class")) {
                        String cname = convertToClassName(WEB_INF_CLASSES,
                                                              pathElement);
                        if (!processClass(cname)) {
                            continue;
                        }
                        if (containsAnnotation(sc, pathElement)) {
                            if (LOGGER.isLoggable(Level.FINE)) {
                                LOGGER.log(Level.FINE,
                                           "[WEB-INF/classes] Found annotated Class: {0}",
                                           cname);
                            }
                            classList.add(cname);
                        }
                    }
                }
            }
        }

    }


    /**
     * @param sc the <code>ServletContext</code> for the application being
     *  scanned
     * @param pathElement the full path to the classfile to be scanned
     * @return <code>true</code> if the class contains one of the Faces
     *  configuration annotations
     */
    private boolean containsAnnotation(ServletContext sc, String pathElement) {

        ReadableByteChannel channel = null;
        try {
            URL url = sc.getResource(pathElement);
            channel = Channels.newChannel(url.openStream());
            return classFileScanner.containsAnnotation(channel);
        } catch (MalformedURLException e) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE,
                           e.toString(),
                           e);
            }
        } catch (IOException ioe) {
            if (LOGGER.isLoggable(Level.SEVERE)) {
                LOGGER.log(Level.SEVERE,
                           ioe.toString(),
                           ioe);
            }
        } finally {
            if (channel != null) {
                try {
                    channel.close();
                } catch (IOException ignored) {
                    if (LOGGER.isLoggable(Level.FINE)) {
                        LOGGER.log(Level.FINE,
                                   ignored.toString(),
                                   ignored);
                    }
                }
            }
        }
        return false;

    }


    /**
     * Utility method for converting paths to fully qualified class names.
     *
     * @param pathEntry a path entry to a class file
     *
     * @return a fully qualfied class name using dot notation
     */
    private String convertToClassName(String pathEntry) {

        return convertToClassName(null, pathEntry);

    }


    /**
     * Utility method for converting paths to fully qualified class names.
     *
     * @param prefix the prefix that should be stripped from the class name
     *  before converting it
     * @param pathEntry a path to a class file
     *
     * @return a fully qualfied class name using dot notation
     */
    private String convertToClassName(String prefix, String pathEntry) {

        String className = pathEntry;

        if (prefix != null) {
            // remove the prefix
            className = className.substring(prefix.length());
        }
        // remove the .class suffix
        className = className.substring(0, (className.length() - 6));

        return className.replace('/', '.');

    }




    // ----------------------------------------------------------- Inner Classes


    /**
     * This class is encapsulating binary .class file information as defined at
     * http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html
     * <p/>
     * This is used by the annotation frameworks to quickly scan .class files
     * for the presence of annotations. This avoid the annotation framework
     * having to load each .class file in the class loader.
     * <p/>
     * Taken from the GlassFish V2 source base.
     */
    @SuppressWarnings("unused")
    private static final class ClassFile {

        private static final int magic = 0xCAFEBABE;

        public static final int ACC_PUBLIC = 0x1;
        public static final int ACC_PRIVATE = 0x2;
        public static final int ACC_PROTECTED = 0x4;
        public static final int ACC_STATIC = 0x8;
        public static final int ACC_FINAL = 0x10;
        public static final int ACC_SYNCHRONIZED = 0x20;
        public static final int ACC_THREADSAFE = 0x40;
        public static final int ACC_TRANSIENT = 0x80;
        public static final int ACC_NATIVE = 0x100;
        public static final int ACC_INTERFACE = 0x200;
        public static final int ACC_ABSTRACT = 0x400;

  public short majorVersion;
        public short minorVersion;
        public ConstantPoolInfo constantPool[];
        public short accessFlags;
        public ConstantPoolInfo thisClass;
        public ConstantPoolInfo superClass;
        public ConstantPoolInfo interfaces[];

        /**
         * bunch of stuff I really don't care too much for now.
         * <p/>
         * FieldInfo           fields[]; MethodInfo          methods[];
         * AttributeInfo       attributes[];
         */

        ByteBuffer header;
        ConstantPoolInfo constantPoolInfo = new ConstantPoolInfo();

        // ------------------------------------------------------------ Constructors

        /**
         * Creates a new instance of ClassFile
         */
        public ClassFile() {
            header = ByteBuffer.allocate(12000);
        }

        // ---------------------------------------------------------- Public Methods


        public void setConstantPoolInfo(ConstantPoolInfo poolInfo) {
            constantPoolInfo = poolInfo;
        }


        /**
         * Read the input channel and initialize instance data structure.
         *
         * @param in a <code>ReadableByteChannel</code> that provides the bytes
         *  of the classfile
         *
         * @return <code>true</code> if the bytes representing this classfile include
         *  one of the annotations we're looking for.
         *
         * @throws IOException if an I/O error occurs while reading the class
         */
        public boolean containsAnnotation(ReadableByteChannel in)
              throws IOException {

            /**
             * this is the .class file layout
             *
             ClassFile {
             u4 magic;
             u2 minor_version;
             u2 major_version;
             u2 constant_pool_count;
             cp_info constant_pool[constant_pool_count-1];
             u2 access_flags;
             u2 this_class;
             u2 super_class;
             u2 interfaces_count;
             u2 interfaces[interfaces_count];
             u2 fields_count;
             field_info fields[fields_count];
             u2 methods_count;
             method_info methods[methods_count];
             u2 attributes_count;
             attribute_info attributes[attributes_count];
             }
             **/
            header.clear();
            long read = (long) in.read(header);
            if (read == -1) {
                return false;
            }
            header.rewind();

            if (header.getInt() != magic) {
                return false;
            }

            minorVersion = header.getShort();
            majorVersion = header.getShort();
            int constantPoolSize = header.getShort();

            return constantPoolInfo
                  .containsAnnotation(constantPoolSize, header, in);

        }

    } // END ClassFile

    private static class ConstantPoolInfo {

        private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();

        public static final byte CLASS = 7;
        public static final int FIELDREF = 9;
        public static final int METHODREF = 10;
        public static final int STRING = 8;
        public static final int INTEGER = 3;
        public static final int FLOAT = 4;
        public static final int LONG = 5;
        public static final int DOUBLE = 6;
        public static final int INTERFACEMETHODREF = 11;
        public static final int NAMEANDTYPE = 12;
        public static final int ASCIZ = 1;
        public static final int UNICODE = 2;

        byte[] bytes = new byte[Short.MAX_VALUE];

        // ------------------------------------------------------------ Constructors

        /**
         * Creates a new instance of ConstantPoolInfo
         */
        public ConstantPoolInfo() {
        }

        // ---------------------------------------------------------- Public Methods

        /**
         * Read the input channel and initialize instance data structure.
         *
         * @param constantPoolSize the constant pool size for this class file
         * @param buffer the ByteBuffer used to store the bytes from <code>in</code>
         * @param in ReadableByteChannel from which the class file bytes are
         *  read
         *
         * @return <code>true</code> if the bytes representing this classfile include
         *  one of the annotations we're looking for.
         *
         * @throws IOException if an I/O error occurs while reading the class
         */
        public boolean containsAnnotation(int constantPoolSize,
                                          final ByteBuffer buffer,
                                          final ReadableByteChannel in)
        throws IOException {

            for (int i = 1; i < constantPoolSize; i++) {
                if (!refill(buffer, in, 1)) {
                    return true;
                }
                final byte type = buffer.get();
                switch (type) {
                    case ASCIZ:
                    case UNICODE:
                        if (!refill(buffer, in, 2)) {
                            return true;
                        }
                        final short length = buffer.getShort();
                        if (length < 0 || length > Short.MAX_VALUE) {
                            return true;
                        }
                        if (length > buffer.capacity()) {
                            return true;
                        }
                        if (!refill(buffer, in, length)) {
                            return true;
                        }
                        buffer.get(bytes, 0, length);
                        /* to speed up the process, I am comparing the first few
                         * bytes to Ljava since all annotations are in the java
                         * package, the reduces dramatically the number or String
                         * construction
                         */
                        if (bytes[0] == 'L' && bytes[1] == 'j' && bytes[2] == 'a') {
                            String stringValue;
                            if (type == ASCIZ) {
                                stringValue =
                                      new String(bytes, 0, length, "US-ASCII");
                            } else {
                                stringValue = new String(bytes, 0, length);
                            }
                            if (JBossJavaClassScanningAnnotationScanner.isAnnotation(stringValue)) {
                                return true;
                            }
                        }
                        break;
                    case CLASS:
                    case STRING:
                        if (!refill(buffer, in, 2)) {
                            return true;
                        }
                        buffer.getShort();
                        break;
                    case FIELDREF:
                    case METHODREF:
                    case INTERFACEMETHODREF:
                    case INTEGER:
                    case FLOAT:
                        if (!refill(buffer, in, 4)) {
                            return true;
                        }
                        buffer.position(buffer.position() + 4);
                        break;
                    case LONG:
                    case DOUBLE:
                        if (!refill(buffer, in, 8)) {
                            return true;
                        }
                        buffer.position(buffer.position() + 8);
                        // for long, and double, they use 2 constantPool
                        i++;
                        break;
                    case NAMEANDTYPE:
                        if (!refill(buffer, in, 4)) {
                            return true;
                        }
                        buffer.getShort();
                        buffer.getShort();
                        break;
                    default:
                        if (LOGGER.isLoggable(Level.SEVERE)) {
                            LOGGER.log(Level.SEVERE,
                                       "Unknow type constant pool {0} at position {1}",
                                       new Object[]{type, i});
                        }
                        break;
                }
            }
            return false;
        }

        // Private Methods
        private boolean refill(ByteBuffer buffer,
                               ReadableByteChannel in,
                               int requestLen) throws IOException {
            
            int cap = buffer.capacity();
            if (buffer.position() + requestLen > cap) {
                buffer.compact();
                int read = in.read(buffer);
                if (read < 0) {
                    return false;
                }
                buffer.rewind();
            }
            return true;        }
    } // END ConstantPoolInfo

}


This hack is based on this post.

This is a known issue resolved at JBoss AS 6.1.0.Final. For those who have to use JBoss AS 6.0.0.Final or any 6.x version older than or equal to 6.0.0.Final, is recommended to upgrade JSF implementation to JSF2, since this issue only occur with JSF2 based libraries, as explained on this article.