On Jan 8, 2009, at 12:30 AM, Marcin Kwapisz wrote:

I think this property should be set in System, not in InitialContext.

System
.setProperty("log4j.category.OpenEJB.startup.attributes","DEBUG");

I'm not sure if you're stating a preference or reporting that setting via InitialContext didn't work. Both approaches should work in the current release.

Scenario 1.
--EJB--
@RolesAllowed({"StudentAdmin"})
   public void createStudent
--EJB--

--ejb-jar.xml--
<assembly-descriptor>
       <security-role>
           <role-name>SysAdmin</role-name>
       </security-role>
       <method-permission>
           <role-name>SysAdmin</role-name>
           <method>
               <ejb-name>StudentEndpoint</ejb-name>
               <method-name>createStudent</method-name>
           </method>
       </method-permission>
--ejb-jar.xml--

DEBUG - Security Attribute: public void pl .zsk .sos .ejb .endpoint .StudentEndpointBean .createStudent(pl.zsk.sos.dto.StudentDTO,pl.zsk.sos.dto.AccountDTO) throws pl.zsk.sos.exception.StudentException -- StudentEndpoint : * : pl.zsk.sos.ejb.endpoint.StudentEndpointBean : createStudent(pl.zsk.sos.dto.StudentDTO, pl.zsk.sos.dto.AccountDTO) StudentAdmin

Scenario 2.
ejb-jar.xml unchanged
RolesAllowed annotation is commented in createStudent as follows
--EJB--
//@RolesAllowed({"StudentAdmin"})
   public void createStudent
--EJB--

DEBUG - Security Attribute: public void pl .zsk .sos .ejb .endpoint .StudentEndpointBean .createStudent(pl.zsk.sos.dto.StudentDTO,pl.zsk.sos.dto.AccountDTO) throws pl.zsk.sos.exception.StudentException -- StudentEndpoint : * : * : createStudent(*) SysAdmin

Ok, it's all coming back to me. I recall what is going on here. Two things first:

1. If you modify your override to be more specific (i.e. include the exact method signature) it will work:
       <method-permission>
           <role-name>SysAdmin</role-name>
           <method>
               <ejb-name>StudentEndpoint</ejb-name>
               <method-name>createStudent</method-name>
               <method-params>
<method-param>pl.zsk.sos.dto.StudentDTO</method- param> <method-param>pl.zsk.sos.dto.AccountDTO</method- param>
               </method-params>
           </method>
       </method-permission>

2. If you'd rather not have to do that and want it to work like Glassfish we can totally do that -- it's not there now but we can add it.


-- FOR THE CURIOUS ---

That said here is the logic behind how it works. Say you have an EJB like this (same applies to transaction annotations):

    @RolesAllowed("ADMIN")
    public static class ColorBean implements ColorLocal, ColorRemote {

        @RolesAllowed("USER")
        public void color(){}

        @RolesAllowed("MANAGER")
        public void color(Object o){}

        public void color(String s){}
        public void color(Boolean b){}
        public void color(Integer i){}
    }

Which yields this:

   - color() : USER
   - color(Object o) : MANAGER
   - color(String s) : ADMIN
   - color(Boolean b) : ADMIN
   - color(Integer i) : ADMIN

Now say you want to override just that usage of ADMIN at the class level to use say SUPERUSER instead and have it work *exactly* as it would as if you had used @RolesAllowed("SUPERUSER") on the class instead of @RolesAllowed("SUPERUSER"). With OpenEJB, you simply do this:

       <method-permission>
           <role-name>SUPERUSER</role-name>
            <method>
                <ejb-name>ColorBean</ejb-name>
            </method>
       </method-permission>

Then we will apply the override to the class level just as if you had used @RolesAllowed("SUPERUSER") which yields:

   - color() : USER
   - color(Object o) : MANAGER
   - color(String s) : SUPERUSER
   - color(Boolean b) : SUPERUSER
   - color(Integer i) : SUPERUSER

We achieve this by translating the annotation into their *exact* xml equivalent and processing them together as if everything had been declared in xml. So this annotation data ...

    @RolesAllowed("ADMIN")
    public static class ColorBean implements ColorLocal, ColorRemote {

        @RolesAllowed("USER")
        public void color(){}

        @RolesAllowed("MANAGER")
        public void color(Object o){}

        public void color(String s){}
        public void color(Boolean b){}
        public void color(Integer i){}
    }

... becomes this xml (added ids for descriptive purposes, they have no affect on anything)...

       <method-permission id="A">
           <role-name>ADMIN</role-name>
            <method>
                <ejb-name>ColorBean</ejb-name>
            </method>
       </method-permission>
       <method-permission id="B">
           <role-name>USER</role-name>
            <method>
                <ejb-name>ColorBean</ejb-name>
                <method-name>color</method-name>
                <method-params/>
            </method>
       </method-permission>
       <method-permission id="C">
           <role-name>MANAGER</role-name>
            <method>
                <ejb-name>ColorBean</ejb-name>
                <method-name>color</method-name>
                <method-params>
                   <method-param>java.lang.Object</method-param>
                </method-params>
            </method>
       </method-permission>

The rules for processing <method-permission> or <container- transaction> attributes in xml dictate that more specific declarations win over the more general ones. So for the method "color(Object o)" the declaration A, which applies to the bean, looses out to declaration C, which applies to an exact method of the bean. So (the part you've been waiting for), if say this xml declaration was added (notice no params specified).

       <method-permission id="D">
           <role-name>SUPERUSER</role-name>
            <method>
                <ejb-name>ColorBean</ejb-name>
                <method-name>color</method-name>
            </method>
       </method-permission>

This style declaration per spec rules would be considered more specific declaration A as it specifies the method name but still less specific than declarations B and C as it does not specify the exact method arguments. This is why when you added the xml declaration it did not affect methods which had more specific declarations in xml (albeit automatically created from annotation data rather than typed in by you). This is something the spec does not really go into detail on, unfortunately, though I have brought it up as a candidate for clarification. I should really do that again before EJB 3.1 goes out the door.


-- FOR THE REALLY CURIOUS ---

That said, there are some very interesting rules for annotation inheritance in the spec for which there is no clear xml overriding support. Read on only if you are interested, otherwise feel free to stop here :)

Given this inheritance chain (switching to transaction annotations for simplicity).

    @TransactionAttribute(MANDATORY)
    public static class Color implements ColorLocal, ColorRemote {

        @TransactionAttribute(NEVER)
        public void color(){}

        @TransactionAttribute(REQUIRES_NEW)
        public void color(Object o){}

        public void color(String s){}
        public void color(Boolean b){}
        public void color(Integer i){}
    }

    @Stateless
    public static class Red extends Color {

        public void color(Object o){super.color(o);}

        @TransactionAttribute(REQUIRES_NEW)
        public void red(){}

        public void red(Object o){}
        public void red(String s){}

    }

Per spec rules, the resulting attributes for the methods of the Red ejb will be as follows:

   - color() : NEVER
   - color(String s) : MANDATORY
   - color(Boolean b) : MANDATORY
   - color(Integer i) : MANDATORY
   - color(Object o) : REQUIRED
   - red() : REQUIRES_NEW
   - red(Object o) : REQUIRED
   - red(String s) : REQUIRED

This methods "red(Object)" and "red(String)" are tx REQUIRED because the usage of @TransactionAttribute(MANDATORY) in the parent class Color is *not* inherited by Red. Additionally since Red did not specify a class-level @TransactionAttribute annotation the default of REQUIRED is use which affects only the methods which are declared in the Red class -- the methods of the parent class Color still use @TransactionAttribute(MANDATORY) unless otherwise specified. The method "color()" was annotated in the parent class as @TransactionAttribute(NEVER), but has been overridden in the child class Red where an @TransactionAttribute annotation was not explicitly supplied, therefor the tx attribute of "color()" becomes that of the Red class and is now @TransactionAttribute(REQUIRED) and no longer @TransactionAttribute(NEVER).

Since annotations can be declared in a "layered cake" style with each parent class in the inheritance chain having the ability to specify its own class-level annotation which affects only it's methods, you need some way to do this in xml. Unfortunately, in this regard there was not enough standard xml elements to do so. We didn't stop there of course and added new <class> level element that allows you target your override to a specific class just as you can with an annotation. It has also been proposed in EJB 3.1 -- one more thing I need to follow up on before the spec goes final.

It works like this. Say you want to override the default transaction attribute for the Red class to be MANDATORY and the default for the class Color to be REQUIRED just as if you had applied @TransactionAttribute(MANDATORY) to the Red class and @TransactionAttribute(REQUIRED) to the Color class. You could do so with an xml declaration like this:

        <container-transaction>
            <trans-attribute>Required</trans-attribute>
            <method>
                <ejb-name>Red</ejb-name>
<class>org.superbiz.Color</class> <!-- not in EJB 3.0 schema -->
            </method>
        </container-transaction>
        <container-transaction>
            <trans-attribute>Mandatory</trans-attribute>
            <method>
                <ejb-name>Red</ejb-name>
<class>org.superbiz.Red</class> <!-- not in EJB 3.0 schema -->
            </method>
        </container-transaction>

That would give you these transaction attributes:

   - color() : NEVER
   - color(String s) : REQUIRED
   - color(Boolean b) : REQUIRED
   - color(Integer i) : REQUIRED
   - color(Object o) : MANDATORY
   - red() : REQUIRES_NEW
   - red(Object o) : MANDATORY
   - red(String s) : MANDATORY

An alternative proposal would be to allow the existing <method-inf> to specify the class name rather than adding a new <class> element. The long and short of it is that we do support xml and xml overrides with the exact same expressive power as annotations have. Definitely something we'd like to see in the spec.

Congrats to those who made it this far :) Feel free to as questions if you have them.

-David

Reply via email to