BusinessInterfaces xml = new BusinessInterfaces();
xml.addLocals(sessionBean.getBusinessLocal(), ejbModule.getClassLoader());
xml.addRemotes(sessionBean.getBusinessRemote(), ejbModule.getClassLoader());
if (beanClass.getAnnotation(LocalBean.class) != null) {
sessionBean.setLocalBean(new Empty());
}
/**
* Anything declared as both <business-local> and <business-remote> is invalid in strict mode
*/
if (strict) for (Class interfce : xml.local) {
if (xml.remote.contains(interfce)) {
validation.fail(ejbName, "xml.localRemote.conflict", interfce.getName());
}
}
/**
* Merge the xml declared business interfaces into the complete set
*/
BusinessInterfaces all = new BusinessInterfaces();
all.local.addAll(xml.local);
all.remote.addAll(xml.remote);
final List<Class<?>> classes = strict ? new ArrayList(asList(beanClass)) : Classes.ancestors(beanClass);
for (Class<?> clazz : classes) {
/*
* @WebService
* @WebServiceProvider
*/
if (sessionBean.getServiceEndpoint() == null) {
Class defaultEndpoint = BeanContext.ServiceEndpoint.class;
for (Class interfce : clazz.getInterfaces()) {
if (interfce.isAnnotationPresent(WebService.class)) {
defaultEndpoint = interfce;
}
}
WebService webService = clazz.getAnnotation(WebService.class);
if (webService != null) {
String className = webService.endpointInterface();
if (!className.equals("")) {
sessionBean.setServiceEndpoint(className);
} else {
sessionBean.setServiceEndpoint(defaultEndpoint.getName());
}
} else if (clazz.isAnnotationPresent(WebServiceProvider.class)) {
sessionBean.setServiceEndpoint(defaultEndpoint.getName());
} else if (!defaultEndpoint.equals(BeanContext.ServiceEndpoint.class)) {
sessionBean.setServiceEndpoint(defaultEndpoint.getName());
}
}
/*
* These interface types are not eligable to be business interfaces.
* java.io.Serializable
* java.io.Externalizable
* javax.ejb.*
*/
List<Class<?>> interfaces = new ArrayList<Class<?>>();
if (!clazz.isInterface()) { // dynamic proxy implementation
for (Class<?> interfce : clazz.getInterfaces()) {
String name = interfce.getName();
if (!name.equals("java.io.Serializable") &&
!name.equals("java.io.Externalizable") &&
!name.startsWith("javax.ejb.") &&
!descriptor.contains(interfce.getName()) &&
!interfce.isSynthetic() &&
!"net.sourceforge.cobertura.coveragedata.HasBeenInstrumented".equals(name) &&
!name.startsWith("org.scalatest.")) {
interfaces.add(interfce);
}
}
}
/**
* Anything discovered and delcared in a previous loop
* or at the beginning in the deployment descriptor is
* not eligable to be redefined.
*/
interfaces.removeAll(all.local);
interfaces.removeAll(all.remote);
/**
* OK, now start checking the class metadata
*/
Local local = clazz.getAnnotation(Local.class);
Remote remote = clazz.getAnnotation(Remote.class);
boolean impliedLocal = local != null && local.value().length == 0;
boolean impliedRemote = remote != null && remote.value().length == 0;
/**
* This set holds the values of @Local and @Remote
* when applied to the bean class itself
*
* These declarations override any similar declaration
* on the interface.
*/
BusinessInterfaces bean = new BusinessInterfaces();
if (local != null) bean.local.addAll(asList(local.value()));
if (remote != null) bean.remote.addAll(asList(remote.value()));
if (strict) for (Class interfce : bean.local) {
if (bean.remote.contains(interfce)) {
validation.fail(ejbName, "ann.localRemote.conflict", interfce.getName());
}
}
/**
* Anything listed explicitly via @Local or @Remote
* on the bean class does not need to be investigated.
* We do not need to check these interfaces for @Local or @Remote
*/
interfaces.removeAll(bean.local);
interfaces.removeAll(bean.remote);
if (impliedLocal || impliedRemote) {
if (interfaces.size() != 1) {
/**
* Cannot imply either @Local or @Remote and list multiple interfaces
*/
// Need to extract the class names and append .class to them to show proper validation level 3 message
List<String> interfaceNames = new ArrayList<String>();
for (Class<?> intrfce : interfaces) {
interfaceNames.add(intrfce.getName()+".class");
}
// just warn for @Local since Glassfish supports it even if it is weird
// still fail for @Remote!
if (impliedLocal && local.value().length == 0 && interfaces.size() == 0 && !strict) {
validation.warn(ejbName, "ann.local.forLocalBean", join(", ", interfaceNames));
// we don't go out to let be deployed
} else if (impliedLocal) {
validation.fail(ejbName, "ann.local.noAttributes", join(", ", interfaceNames));
/**
* This bean is invalid, so do not bother looking at the other interfaces or the superclass
*/
return;
}
if (impliedRemote) {
validation.fail(ejbName, "ann.remote.noAttributes", join(", ", interfaceNames));
/**
* This bean is invalid, so do not bother looking at the other interfaces or the superclass
*/
return;
}
} else if (strict && impliedLocal && impliedRemote) {
Class<?> interfce = interfaces.remove(0);
/**
* Cannot imply @Local and @Remote at the same time with strict mode on
*/
validation.fail(ejbName, "ann.localRemote.ambiguous", interfce.getName());
} else {
if (impliedLocal) bean.local.addAll(interfaces);
if (impliedRemote) bean.remote.addAll(interfaces);
interfaces.clear();
}
}
/**
* OK, now start checking the metadata of the interfaces implemented by this class
*/
/**
* This set holds the list of interfaces that the bean implements
* that are annotated either as @Local or @Remote
*
* If the interface is annotated to the contrary in the bean class
* the bean class meta data wins, therefore we track these separately
*
* Ultimately, the deployment descriptor wins over all, so we have tracked
* those declarations separately as well.
*/
BusinessInterfaces implemented = new BusinessInterfaces();
for (Class interfce : interfaces) {
boolean isLocal = interfce.isAnnotationPresent(Local.class);
boolean isRemote = interfce.isAnnotationPresent(Remote.class);
if (strict && isLocal && isRemote) {
validation.fail(ejbName, "ann.localRemote.conflict", interfce.getName());
} else {
Class[] superInterface = interfce.getInterfaces();
if (isLocal) {
if (strict) {
for (Class si : superInterface) {
boolean present = si.isAnnotationPresent(Remote.class);
if (present) {
validation.fail(ejbName, "ann.remoteOrLocal.converse.parent", interfce.getName(), "Local", si.getName(), "Remote");
}
}
}
implemented.local.add(interfce);
}
if (isRemote) {
if (strict) {
for (Class si : superInterface) {
boolean present = si.isAnnotationPresent(Local.class);
if (present) {
validation.fail(ejbName, "ann.remoteOrLocal.converse.parent", interfce.getName(), "Remote", si.getName(), "Local");
}
}
}
implemented.remote.add(interfce);
}
}
}
interfaces.removeAll(implemented.local);
interfaces.removeAll(implemented.remote);
/**
* Merge in class-level metadata.
*
* We've already merged in the xml metadata, so that
* metadata will win over this metadata.
*/
// remove anything we've already seen
bean.local.removeAll(all.local);
bean.local.removeAll(all.remote);
bean.remote.removeAll(all.remote);
bean.remote.removeAll(all.local);
// validate the things we are going to add
for (Class interfce : bean.local) validateLocalInterface(interfce, validation, ejbName);
for (Class interfce : bean.remote) validateRemoteInterface(interfce, validation, ejbName);
// add finally, add them
all.local.addAll(bean.local);
all.remote.addAll(bean.remote);
/**
* Merge in interface-level metadata
*
* We've already merged in the xml metadata *and* class metadata,
* so both of those will win over this metadata.
*/
// remove anything we've already seen
implemented.local.removeAll(all.local);
implemented.local.removeAll(all.remote);
implemented.remote.removeAll(all.remote);
implemented.remote.removeAll(all.local);
// validate the things we are going to add
for (Class interfce : implemented.local) validateLocalInterface(interfce, validation, ejbName);
for (Class interfce : implemented.remote) validateRemoteInterface(interfce, validation, ejbName);
// add the rest
all.local.addAll(implemented.local);
all.remote.addAll(implemented.remote);
// We only consider the top-most class (the bean class itself) when evaluating
// the case of absolutely no metadata at all and attempting to figure out the
// default view which will be implied as either @LocalBean or @Local
if (clazz == beanClass
&& sessionBean.getLocalBean() == null
&& sessionBean.getBusinessLocal().isEmpty()
&& sessionBean.getBusinessRemote().isEmpty()
&& sessionBean.getHome() == null
&& sessionBean.getRemote() == null
&& sessionBean.getLocalHome() == null
&& sessionBean.getLocal() == null
&& sessionBean.getServiceEndpoint() == null
&& all.local.isEmpty()
&& all.remote.isEmpty()
) {
if (interfaces.size() == 0 || DynamicProxyImplFactory.isKnownDynamicallyImplemented(clazz)) {
// No interfaces? Then @LocalBean
sessionBean.setLocalBean(new Empty());
} else if (interfaces.size() == 1) {
// One interface? Then @Local
all.local.add(interfaces.remove(0));
} else {
// Multiple interfaces? Illegal
validation.fail(ejbName, "too.many.interfaces", ejbName, interfaces.toString().replace("interface ", ""));
return;
}
}
//alway set Local View for ManagedBean
if (beanClass.isAnnotationPresent(ManagedBean.class)){
sessionBean.setLocalBean(new Empty());
}
/**
* Track any interfaces we didn't use