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