// if this is a local ref, proceed with resolution only if ejb-link is null
if (!ejbRef.isLocal() || (ejbRef.isLocal() && ejbRef.getLinkName()==null)) {
DOLUtils.getDefaultLogger().fine("Ref " + ejbRef.getName() + " is bound to Ejb with JNDI Name " + ejbRef.getJndiName());
if (getEjbDescriptors() != null) {
for (Iterator iter = getEjbDescriptors().iterator(); iter.hasNext();) {
EjbDescriptor ejb = (EjbDescriptor)iter.next();
if (ejbRef.getJndiName().equals(ejb.getJndiName())) {
ejbRef.setEjbDescriptor(ejb);
return;
}
}
}
}
}
// If the reference does not have an ejb-link or jndi-name associated
// with it, attempt to resolve it by checking against all the ejbs
// within the application. If no match is found, just fall through
// and let the existing error-checking logic kick in.
if (( (ejbRef.getJndiName() == null) ||
(ejbRef.getJndiName().length() == 0) )
&&
( (ejbRef.getLinkName() == null) ||
(ejbRef.getLinkName().length() == 0) )) {
Map<String, EjbIntfInfo> ejbIntfInfoMap = getEjbIntfMap();
if ( ejbIntfInfoMap.size() > 0 ) {
String interfaceToMatch = ejbRef.isEJB30ClientView() ?
ejbRef.getEjbInterface() : ejbRef.getEjbHomeInterface();
EjbIntfInfo intfInfo = ejbIntfInfoMap.get(interfaceToMatch);
// make sure exactly one match
if ( intfInfo != null ) {
int numMatches = intfInfo.ejbs.size();
if( numMatches == 1 ) {
Iterator iter = intfInfo.ejbs.iterator();
EjbDescriptor target = (EjbDescriptor)iter.next();
BundleDescriptor targetModule =
target.getEjbBundleDescriptor();
BundleDescriptor sourceModule =
ejbRef.getReferringBundleDescriptor();
//
// It's much cleaner to derive the ejb-link value
// and set that instead of the descriptor. This way,
// if there are multiple ejb-jars within the .ear that
// each have an ejb with the target bean's ejb-name,
// there won't be any ambiguity about which one is
// the correct target. It's not so much a problem
// during this phase of the processing, but if the
// fully-qualified ejb-link name is required and is not
// written out, there could be non-deterministic
// behavior when the application is re-loaded.
// Let the ejb-link processing logic handle the
// conversion to ejb descriptor.
//
// If the ejb reference and the target ejb are defined
// within the same ejb-jar, the ejb-link will only
// be set to ejb-name. This is done regardless of
// whether the ejb-jar is within an .ear or is
// stand-alone. The ejb-link processing
// logic will always check the current ejb-jar
// first so there won't be any ambiguity.
String ejbLinkName = target.getName();
if( sourceModule != targetModule ) {
// Since there are at least two modules, we
// must be within an application.
String relativeUri = getApplication().
getRelativeUri(sourceModule, targetModule);
ejbLinkName = relativeUri + "#" + ejbLinkName;
}
ejbRef.setLinkName(ejbLinkName);
} else {
String msg = "Cannot resolve reference " + ejbRef +
" because there are " + numMatches + " ejbs " +
" in the application with interface " +
interfaceToMatch;
DOLUtils.getDefaultLogger().severe(msg);
throw new RuntimeException(msg);
}
}
}
}
// now all cases fall back here, we need to resolve through the link-name
if (ejbRef.getLinkName()==null) {
// if no link name if present, and this is a local ref, this is always an
// error because we must resolve all local refs and we cannot resolve it
// throw either the jndi name or the link name
if (ejbRef.isLocal()) {
DOLUtils.getDefaultLogger().severe("Cannot resolve reference " + ejbRef);
throw new RuntimeException("Cannot resolve reference " + ejbRef);
} else {
// this is a remote interface, jndi will eventually contain the referenced
// ejb ref, apply default jndi name if there is none
if (ejbRef.getJndiName() == null ||
ejbRef.getJndiName().length() == 0) {
String jndiName = getDefaultEjbJndiName(
ejbRef.isEJB30ClientView() ?
ejbRef.getEjbInterface() : ejbRef.getEjbHomeInterface());
ejbRef.setJndiName(jndiName);
DOLUtils.getDefaultLogger().fine("Applying default to ejb reference: " + ejbRef);
}
return;
}
}
// Beginning of ejb-link resolution
// save anticipated types for checking if interfaces are compatible
String homeClassName = ejbRef.getEjbHomeInterface();
String intfClassName = ejbRef.getEjbInterface();
// save anticipated type for checking if bean type is compatible
String type = ejbRef.getType();
EjbDescriptor ejbReferee=null;
String linkName = ejbRef.getLinkName();
int ind = linkName.lastIndexOf('#');
if ( ind != -1 ) {
// link has a relative path from referring EJB JAR,
// of form "../products/product.jar#ProductEJB"
String ejbName = linkName.substring(ind+1);
String jarPath = linkName.substring(0, ind);
BundleDescriptor referringJar = ejbRef.getReferringBundleDescriptor();
if (referringJar==null) {
ejbRef.setReferringBundleDescriptor(getBundleDescriptor());
referringJar = getBundleDescriptor();
}
if (getApplication()!=null) {
BundleDescriptor refereeJar =
getApplication().getRelativeBundle(referringJar, jarPath);
if( (refereeJar != null) &&
refereeJar instanceof EjbBundleDescriptor ) {
// this will throw an exception if ejb is not found
ejbReferee =
((EjbBundleDescriptor)refereeJar).getEjbByName(ejbName);
}
}
}
else {
// Handle an unqualified ejb-link, which is just an ejb-name.
// If we're in an application and currently processing an
// ejb-reference defined within an ejb-jar, first check
// the current ejb-jar for an ejb-name match. From a spec
// perspective, the deployer can't depend on this behavior,
// but it's still better to have deterministic results. In
// addition, in the case of automatic-linking, the fully-qualified
// "#" ejb-link syntax is not used when the ejb reference and
// target ejb are within the same ejb-jar. Checking the
// ejb-jar first will ensure the correct linking behavior for
// that case.
if ( (getApplication() != null) && (ejbBundleDescriptor != null)
&& ejbBundleDescriptor.hasEjbByName(linkName) ) {
ejbReferee = ejbBundleDescriptor.getEjbByName(linkName);
} else if ( (getApplication() != null) &&
getApplication().hasEjbByName(linkName)) {
ejbReferee =
getApplication().getEjbByName(ejbRef.getLinkName());
} else if (ejb!=null) {
try {
ejbReferee = ejb.getEjbBundleDescriptor().getEjbByName(ejbRef.getLinkName());
} catch (IllegalArgumentException e) {
// this may happen when we have no application and the ejb ref
// cannot be resolved to a ejb in the bundle. The ref will
// probably be resolved when the application is assembled.
DOLUtils.getDefaultLogger().warning("Unresolved <ejb-link>: "+linkName);
return;
}
}
}
if (ejbReferee==null)
{
// we could not resolve through the ejb-link. if this is a local ref, this
// is an error, if this is a remote ref, this should be also an error at
// runtime but maybe the jndi name will be specified by deployer so
// a warning should suffice
if (ejbRef.isLocal()) {
DOLUtils.getDefaultLogger().severe("Unresolved <ejb-link>: "+linkName);
throw new RuntimeException("Error: Unresolved <ejb-link>: "+linkName);
} else {
DOLUtils.getDefaultLogger().warning("Unresolved <ejb-link>: "+linkName);
return;
}
} else {
if( ejbRef.isEJB30ClientView() ) {
BundleDescriptor referringBundle =
ejbRef.getReferringBundleDescriptor();
// If we can verify that the current ejb 3.0 reference is defined
// in any Application Client module or in a stand-alone web module
// it must be remote business.
if( ( (referringBundle == null) && (ejbBundleDescriptor == null) )
||
(referringBundle instanceof ApplicationClientDescriptor)
||
( (getApplication() == null) &&
(referringBundle instanceof WebBundleDescriptor) ) ) {
ejbRef.setLocal(false);
// Double-check that target has a remote business interface of this
// type. This will handle the common error case that the target
// EJB has intended to support a remote business interface but
// has not used @Remote to specify it, in which case
// the interface was assigned the default of local business.
if( !ejbReferee.getRemoteBusinessClassNames().contains
(intfClassName) ) {
String msg = "Target ejb " + ejbReferee.getName() + " for " +
" remote ejb 3.0 reference " + ejbRef.getName() +
" does not expose a remote business interface of type " +
intfClassName;
throw new RuntimeException(msg);
}
} else if(ejbReferee.getLocalBusinessClassNames().
contains(intfClassName)) {
ejbRef.setLocal(true);
} else if(ejbReferee.getRemoteBusinessClassNames().
contains(intfClassName)) {
ejbRef.setLocal(false);
} else {
String msg = "Warning : Unable to determine local " +
" business vs. remote business designation for " +
" EJB 3.0 ref " + ejbRef;
throw new RuntimeException(msg);
}
}
ejbRef.setEjbDescriptor(ejbReferee);
}
// if we are here, we must have resolved the reference
if(DOLUtils.getDefaultLogger().isLoggable(Level.FINE)) {
DOLUtils.getDefaultLogger().fine("Done Visiting " + ejb.getName() + " reference " + ejbRef);
}
// check that declared types are compatible with expected values
// if there is a target ejb descriptor available
if( ejbReferee != null ) {
if( ejbRef.isEJB30ClientView() ) {
Set<String> targetBusinessIntfs = ejbRef.isLocal() ?
ejbReferee.getLocalBusinessClassNames() :
ejbReferee.getRemoteBusinessClassNames();
if( !targetBusinessIntfs.contains(intfClassName) ) {
DOLUtils.getDefaultLogger().log(Level.WARNING,
"enterprise.deployment.backend.ejbRefTypeMismatch",
new Object[] {ejbRef.getName() , intfClassName,
ejbReferee.getName(), ( ejbRef.isLocal() ?
"Local Business" : "Remote Business"),
targetBusinessIntfs.toString()});
// We can only figure out what the correct type should be
// if there is only 1 target remote/local business intf.
if( targetBusinessIntfs.size() == 1 ) {
Iterator iter = targetBusinessIntfs.iterator();
ejbRef.setEjbInterface((String)iter.next());
}
}
} else {
String targetHome = ejbRef.isLocal() ?
ejbReferee.getLocalHomeClassName() :
ejbReferee.getHomeClassName();
if( !homeClassName.equals(targetHome) ) {
DOLUtils.getDefaultLogger().log(Level.WARNING,
"enterprise.deployment.backend.ejbRefTypeMismatch",
new Object[] {ejbRef.getName() , homeClassName,
ejbReferee.getName(), ( ejbRef.isLocal() ?
"Local Home" : "Remote Home"), targetHome});
if( targetHome != null ) {
ejbRef.setEjbHomeInterface(targetHome);
}
}
String targetComponentIntf = ejbRef.isLocal() ?
ejbReferee.getLocalClassName() :
ejbReferee.getRemoteClassName();
// In some cases for 2.x style @EJBs that point to Entity beans
// the interface class cannot be derived, so only do the
// check if the intf is known.
if( (intfClassName != null) &&
!intfClassName.equals(targetComponentIntf) ) {
DOLUtils.getDefaultLogger().log(Level.WARNING,
"enterprise.deployment.backend.ejbRefTypeMismatch",
new Object[] {ejbRef.getName() , intfClassName,
ejbReferee.getName(), ( ejbRef.isLocal() ?
"Local" : "Remote"), targetComponentIntf});
if( targetComponentIntf != null ) {
ejbRef.setEjbInterface(targetComponentIntf);
}