/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.deployment;
import java.util.*;
import java.net.URI;
import java.net.URISyntaxException;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.deployment.util.ModuleDescriptor;
import com.sun.enterprise.deployment.types.EntityManagerFactoryReference;
import com.sun.enterprise.deployment.types.EntityManagerReference;
import com.sun.enterprise.util.io.FileUtils;
import javax.enterprise.deploy.shared.ModuleType;
import javax.persistence.EntityManagerFactory;
/**
* I am an abstract class representing all the deployment information common
* to all component container structures held by an application.
*
* @author Danny Coward
*/
public abstract class BundleDescriptor extends RootDeploymentDescriptor implements Roles {
private static LocalStringManagerImpl localStrings =
new LocalStringManagerImpl(BundleDescriptor.class);
private final static String DEPLOYMENT_DESCRIPTOR_DIR="META-INF";
private final static String WSDL_DIR="wsdl";
// the spec versions we should start to look at annotations
private final static double ANNOTATION_EJB_VER = 3.0;
private final static double ANNOTATION_WAR_VER = 2.5;
private final static double ANNOTATION_CAR_VER = 5.0;
private final String PERSISTENCE_UNIT_NAME_SEPARATOR = "#";
private Application application;
private Set roles;
private Set messageDestinations = new HashSet();
private WebServicesDescriptor webServices = new WebServicesDescriptor();
private boolean fullFlag = false;
private boolean fullAttribute = false;
// Physical entity manager factory corresponding to the unit name of
// each module-level persistence unit. Only available at runtime.
private Map<String, EntityManagerFactory> entityManagerFactories =
new HashMap<String, EntityManagerFactory>();
/**
* contains the information for this module (like it's module name)
*/
private ModuleDescriptor moduleDescriptor;
// table for caching InjectionInfo with the class name as index
private Hashtable<InjectionInfoCacheKey, InjectionInfo> injectionInfos =
new Hashtable<InjectionInfoCacheKey, InjectionInfo>();
/**
* Construct a new BundleDescriptor
*/
public BundleDescriptor() {
super();
webServices.setBundleDescriptor(this);
}
/**
* Construct a new BundleDescriptor with a name and description
*/
public BundleDescriptor(String name, String description) {
super(name, description);
webServices.setBundleDescriptor(this);
}
/**
* Sets the application to which I belong.
*/
public void setApplication (Application a) {
if (this.application != null) {
this.removeNotificationListener(this.application);
}
this.application = a;
if (this.application != null) {
this.addNotificationListener(this.application);
}
}
void addBundleDescriptor(BundleDescriptor bundleDescriptor) {
this.getRoles().addAll(bundleDescriptor.getRoles());
this.changed();
}
/**
* @return true if this module is an application object
*/
public boolean isApplication() {
return false;
}
/**
* The application to which I belong, or none if I am standalone.
*/
public Application getApplication() {
return this.application;
}
/**
* Set the physical entity manager factory for a persistence unit
* within this module.
*/
public void addEntityManagerFactory(String unitName,
EntityManagerFactory emf) {
entityManagerFactories.put(unitName, emf);
}
/**
* Retrieve the physical entity manager factory associated with the
* unitName of a persistence unit within this module. Returns null if
* no matching entry is found.
*/
public EntityManagerFactory getEntityManagerFactory(String unitName) {
return entityManagerFactories.get(unitName);
}
/**
* Returns the set of physical entity manager factories associated
* with persistence units in this module.
*/
public Set<EntityManagerFactory> getEntityManagerFactories() {
return new HashSet<EntityManagerFactory>
(entityManagerFactories.values());
}
/**
* @return a set of service-ref from this bundle or an empty set
* if none
*/
public abstract Set getServiceReferenceDescriptors();
/**
* Return web services defined for this module. Not applicable for
* application clients.
*/
public WebServicesDescriptor getWebServices() {
return webServices;
}
public WebServiceEndpoint getWebServiceEndpointByName(String name) {
return webServices.getEndpointByName(name);
}
/**
* @return true if this bundle descriptor defines web service clients
*/
public boolean hasWebServiceClients() {
return false;
}
/**
* @return true if this bundle descriptor defines web services
*/
public boolean hasWebServices() {
return getWebServices().hasWebServices();
}
/**
* Return the Set of message destinations I have
*/
public Set getMessageDestinations() {
if (this.messageDestinations == null) {
this.messageDestinations = new HashSet();
}
return this.messageDestinations;
}
/**
* Returns true if I have an message destiation by that name.
*/
public boolean hasMessageDestinationByName(String name) {
for (Iterator itr = this.getMessageDestinations().iterator();
itr.hasNext();) {
Descriptor next = (Descriptor) itr.next();
if (next.getName().equals(name)) {
return true;
}
}
return false;
}
/**
* Returns a message destination descriptor that I have by the
* same name, or throws an IllegalArgumentException
*/
public MessageDestinationDescriptor getMessageDestinationByName
(String name) {
for (Iterator itr = this.getMessageDestinations().iterator();
itr.hasNext();) {
Descriptor next = (Descriptor) itr.next();
if (next.getName().equals(name)) {
return (MessageDestinationDescriptor) next;
}
}
throw new IllegalArgumentException(localStrings.getLocalString(
"enterprise.deployment.exceptionmessagedestbundle",
"Referencing error: this bundle has no message destination of name: {0}", new Object[] {name}));
}
/**
* Add a message destination to me.
*/
public void addMessageDestination(MessageDestinationDescriptor
messageDestination) {
messageDestination.setBundleDescriptor(this);
this.getMessageDestinations().add(messageDestination);
super.changed();
}
/**
* Remove the given message destination descriptor from my (by equality).
*/
public void removeMessageDestination(MessageDestinationDescriptor msgDest) {
msgDest.setBundleDescriptor(null);
this.getMessageDestinations().remove(msgDest);
super.changed();
}
/**
* Return the set of com.sun.enterprise.deployment.Role objects
* I have plus the ones from application
*/
public Set getRoles() {
if (this.roles == null) {
this.roles = new OrderedSet();
}
if (application != null) {
this.roles.addAll(application.getAppRoles());
}
return this.roles;
}
/**
*Adds a role object to me.
*/
public void addRole(Role role) {
this.getRoles().add(role);
this.changed();
}
/**
*Adds a Role object based on the supplied SecurityRoleDescriptor.
*<p>
*A change in SecurityRoleNode to fix bug 4933385 causes the DOL to use SecurityRoleDescriptor, rather
*than Role, to contain information about security roles. To minimize the impact on BundleDescriptor,
*this method has been added for use by the DOL as it processes security-role elements.
*<p>
*This method creates a new Role object based on the characteristics of the SecurityRoleDescriptor
*and then delegates to addRole(Role) to preserve the rest of the behavior of this class.
*
*@param descriptor SecurityRoleDescriptor that describes the username and description of the role
*/
public void addRole(SecurityRoleDescriptor descriptor) {
Role role = new Role(descriptor.getName());
role.setDescription(descriptor.getDescription());
this.addRole(role);
}
/**
* Removes a role object from me.
*/
public void removeRole(Role role) {
this.getRoles().remove(role);
this.changed();
}
/**
* Utility method for iterating the set of named descriptors in the supplied nameEnvironment
*/
protected Collection getNamedDescriptorsFrom(JndiNameEnvironment nameEnvironment) {
Collection namedDescriptors = new Vector();
for (Iterator itr = nameEnvironment.getResourceReferenceDescriptors().iterator(); itr.hasNext();) {
ResourceReferenceDescriptor resourceReference = (ResourceReferenceDescriptor) itr.next();
namedDescriptors.add(resourceReference);
}
for (Iterator itr = nameEnvironment.getEjbReferenceDescriptors().iterator(); itr.hasNext();) {
EjbReferenceDescriptor ejbReference = (EjbReferenceDescriptor) itr.next();
namedDescriptors.add(ejbReference);
}
for (Iterator itr = nameEnvironment.getJmsDestinationReferenceDescriptors().iterator(); itr.hasNext();) {
JmsDestinationReferenceDescriptor resourceEnvRef =
(JmsDestinationReferenceDescriptor) itr.next();
namedDescriptors.add(resourceEnvRef);
}
return namedDescriptors;
}
/**
* Utility method for iterating the set of NameReference pairs in the supplied nameEnvironment
*/
protected Vector getNamedReferencePairsFrom(JndiNameEnvironment nameEnvironment) {
Vector pairs = new Vector();
for (Iterator itr = nameEnvironment.getResourceReferenceDescriptors().iterator(); itr.hasNext();) {
ResourceReferenceDescriptor resourceReference = (ResourceReferenceDescriptor) itr.next();
pairs.add(NamedReferencePair.createResourceRefPair((Descriptor)nameEnvironment, resourceReference));
}
for (Iterator itr = nameEnvironment.getEjbReferenceDescriptors().iterator(); itr.hasNext();) {
EjbReferenceDescriptor ejbReference = (EjbReferenceDescriptor) itr.next();
pairs.add(NamedReferencePair.createEjbRefPair((Descriptor) nameEnvironment, ejbReference));
}
for (Iterator itr = nameEnvironment.getJmsDestinationReferenceDescriptors().iterator(); itr.hasNext();) {
JmsDestinationReferenceDescriptor resourceEnvRef =
(JmsDestinationReferenceDescriptor) itr.next();
pairs.add(NamedReferencePair.createResourceEnvRefPair((Descriptor) nameEnvironment, resourceEnvRef));
}
return pairs;
}
private static final class InjectionInfoCacheKey {
String beanName;
Class clazz;
int hc;
InjectionInfoCacheKey(String beanName, Class clazz) {
this.beanName = beanName;
this.clazz = clazz;
hc = beanName.hashCode();
}
public int hashCode() {
return hc;
}
public boolean equals(Object o) {
boolean result = false;
if (o instanceof InjectionInfoCacheKey) {
InjectionInfoCacheKey other = (InjectionInfoCacheKey) o;
if (hc == other.hc) {
return ((clazz == other.clazz) && (beanName.equals(other.beanName)));
}
}
return result;
}
}
public InjectionInfo getInjectionInfoByClass(Class clazz,
JndiNameEnvironment jndiNameEnv) {
// first look in the cache
InjectionInfoCacheKey key = null;
if (jndiNameEnv instanceof EjbDescriptor) {
EjbDescriptor jndiEjbDesc = (EjbDescriptor) jndiNameEnv;
key = new InjectionInfoCacheKey(jndiEjbDesc.getName(), clazz);
} else {
key = new InjectionInfoCacheKey(clazz.getName(), clazz);
}
InjectionInfo injectionInfo = injectionInfos.get(key);
if (injectionInfo != null) {
return injectionInfo;
}
String className = clazz.getName();
// if it's not in the cache, create a new one
LifecycleCallbackDescriptor postConstructDesc =
getPostConstructDescriptorByClass(className, jndiNameEnv);
String postConstructMethodName = (postConstructDesc != null) ?
postConstructDesc.getLifecycleCallbackMethod() : null;
LifecycleCallbackDescriptor preDestroyDesc =
getPreDestroyDescriptorByClass(className, jndiNameEnv);
String preDestroyMethodName = (preDestroyDesc != null) ?
preDestroyDesc.getLifecycleCallbackMethod() : null;
injectionInfo = new InjectionInfo(className,
postConstructMethodName, preDestroyMethodName,
getInjectableResourcesByClass(className,
jndiNameEnv));
// store it in the cache and return
injectionInfos.put(key, injectionInfo);
return injectionInfo;
}
public LifecycleCallbackDescriptor
getPostConstructDescriptorByClass(String className,
JndiNameEnvironment jndiNameEnv)
{
for (LifecycleCallbackDescriptor next :
jndiNameEnv.getPostConstructDescriptors()) {
if (next.getLifecycleCallbackClass().equals(className)) {
return next;
}
}
return null;
}
public LifecycleCallbackDescriptor
getPreDestroyDescriptorByClass(String className,
JndiNameEnvironment jndiNameEnv)
{
for (LifecycleCallbackDescriptor next :
jndiNameEnv.getPreDestroyDescriptors()) {
if (next.getLifecycleCallbackClass().equals(className)) {
return next;
}
}
return null;
}
protected List<InjectionCapable> getInjectableResources
(JndiNameEnvironment jndiNameEnv) {
List<InjectionCapable> injectables =
new LinkedList<InjectionCapable>();
Collection allEnvProps = new HashSet();
for(Iterator envEntryItr =
jndiNameEnv.getEnvironmentProperties().iterator();
envEntryItr.hasNext();) {
EnvironmentProperty envEntry = (EnvironmentProperty)
envEntryItr.next();
// Only env-entries that have been assigned a value are
// eligible for injection.
if( envEntry.hasAValue() ) {
allEnvProps.add(envEntry);
}
}
allEnvProps.addAll(jndiNameEnv.getEjbReferenceDescriptors());
allEnvProps.addAll(jndiNameEnv.getServiceReferenceDescriptors());
allEnvProps.addAll(jndiNameEnv.getResourceReferenceDescriptors());
allEnvProps.addAll(jndiNameEnv.getJmsDestinationReferenceDescriptors());
allEnvProps.addAll(jndiNameEnv.getMessageDestinationReferenceDescriptors());
allEnvProps.addAll(jndiNameEnv.getEntityManagerFactoryReferenceDescriptors());
allEnvProps.addAll(jndiNameEnv.getEntityManagerReferenceDescriptors());
for(Iterator envItr = allEnvProps.iterator(); envItr.hasNext();) {
InjectionCapable next = (InjectionCapable) envItr.next();
if( next.isInjectable() ) {
injectables.add(next);
}
}
return injectables;
}
/**
* Define implementation of getInjectableResourceByClass here so it
* isn't replicated across appclient, web, ejb descriptors.
*/
protected List<InjectionCapable>
getInjectableResourcesByClass(String className,
JndiNameEnvironment jndiNameEnv) {
List<InjectionCapable> injectables =
new LinkedList<InjectionCapable>();
for(InjectionCapable next : getInjectableResources(jndiNameEnv) ) {
if( next.isInjectable()) {
for (InjectionTarget target : next.getInjectionTargets()) {
if (target.getClassName().equals(className) ) {
injectables.add(next);
}
}
}
}
return injectables;
}
/**
* @return the module descriptor for this bundle
*/
public ModuleDescriptor getModuleDescriptor() {
if (moduleDescriptor==null) {
moduleDescriptor = new ModuleDescriptor();
moduleDescriptor.setModuleType(getModuleType());
moduleDescriptor.setDescriptor(this);
}
return moduleDescriptor;
}
/**
* Sets the module descriptor for this bundle
* @param descriptor for the module
*/
public void setModuleDescriptor(ModuleDescriptor descriptor) {
moduleDescriptor = descriptor;
}
/**
* @return the class loader associated with this module
*/
public ClassLoader getClassLoader() {
if (classLoader!=null) {
return classLoader;
}
if (application!=null) {
return application.getClassLoader();
}
throw new RuntimeException("No class loader associated with this module " + getName());
}
/**
* Prints a formatted string representing my state.
*/
public void print(StringBuffer toStringBuffer) {
toStringBuffer.append("\n");
super.print(toStringBuffer);
toStringBuffer.append("\n Roles[] = ").append(roles);
if (getWebServices().hasWebServices()) {
toStringBuffer.append("\n WebServices ");
((Descriptor)(getWebServices())).print(toStringBuffer);
}
}
/**
* @return the type of this bundle descriptor
*/
public abstract ModuleType getModuleType();
/**
* @return the module ID for this module descriptor
*/
public String getModuleID() {
if (moduleID==null) {
moduleID = getModuleDescriptor().getArchiveUri();
}
if (getModuleDescriptor().isStandalone()) {
return moduleID;
}
if (application!=null) {
if (application.getModuleID()==null) {
return getDisplayName();
}
return application.getModuleID()+"#"+moduleID;
} else {
return moduleID;
}
}
/**
* @return the deployment descriptor directory location inside
* the archive file
*/
public String getDeploymentDescriptorDir() {
return DEPLOYMENT_DESCRIPTOR_DIR;
}
/**
* @return the wsdl directory location inside the archive file
*/
public String getWsdlDir() {
return getDeploymentDescriptorDir() + "/" + WSDL_DIR;
}
/**
* Sets the full flag of the bundle descriptor. Once set, the annotations
* of the classes contained in the archive described by this bundle
* descriptor will be ignored.
* @param flag a boolean to set or unset the flag
*/
public void setFullFlag(boolean flag) {
fullFlag=flag;
}
/**
* Sets the full attribute of the deployment descriptor
* @param value the full attribute
*/
public void setFullAttribute(String value) {
fullAttribute = Boolean.valueOf(value);
}
/**
* Get the full attribute of the deployment descriptor
* @return the full attribute
*/
public boolean isFullAttribute() {
return fullAttribute;
}
/**
* @ return true for following cases:
* 1. When the full attribute is true. This attribute only applies to
* ejb module with schema version equal or later than 3.0;
web module and schema version equal or later than than 2.5;
appclient module and schema version equal or later than 5.0.
* 2. When it's been tagged as "full" when processing annotations.
* 3. When DD has a version which doesn't allowed annotations.
* return false otherwise.
*/
public boolean isFullFlag() {
// if the full attribute is true or it's been tagged as full,
// return true
if (fullAttribute == true || fullFlag == true) {
return true;
}
return isDDWithNoAnnotationAllowed();
}
/**
* @ return true for following cases:
* a. connector module;
* b. ejb module and schema version earlier than 3.0;
* c. web module and schema version earlier than 2.5;
* d. appclient module and schema version earlier than 5.0.
*/
public boolean isDDWithNoAnnotationAllowed() {
ModuleType mType = getModuleType();
double specVersion = Double.parseDouble(getSpecVersion());
// connector DD doesn't have annotation, so always treated
// as full DD
if (mType.equals(ModuleType.RAR)) {
return true;
} else {
// we do not process annotations for earlier versions of DD
if ( (mType.equals(ModuleType.EJB) &&
specVersion < ANNOTATION_EJB_VER) ||
(mType.equals(ModuleType.WAR) &&
specVersion < ANNOTATION_WAR_VER) ||
(mType.equals(ModuleType.CAR) &&
specVersion < ANNOTATION_CAR_VER) ) {
return true;
} else {
return false;
}
}
}
/**
* This method returns all the persistence units that are referenced
* by this module. Depending on the type of component, a PU can be
* referenced by one of the four following ways:
* <persistence-context-ref>, @PersistenceContext,
* <persistence-unit-ref> and @PersistenceUnit
* This method is intentionally not made abstract because we don't
* want every subclass to implement. So, we have a dummy implementation
* that we don't expect to be used ever. See, the actual implementation
* done in EjbBundleDescriptor, ApplicationClientDescriptor and
* WebBundleDescriptor.
*
* @return persistence units that are referenced by this module
*/
public Collection<? extends PersistenceUnitDescriptor> findReferencedPUs() {
/*
* A dummy implementation that we don't expect to be used ever.
*/
assert(false);
return null;
}
/**
* helper method: find all PUs referenced via @PersistenceUnit or
* <persistence-unit-ref>
*/
protected static Collection<? extends PersistenceUnitDescriptor>
findReferencedPUsViaPURefs(JndiNameEnvironment component) {
Collection<PersistenceUnitDescriptor> pus =
new HashSet<PersistenceUnitDescriptor>();
for(EntityManagerFactoryReference emfRef :
component.getEntityManagerFactoryReferenceDescriptors()) {
final String unitName = emfRef.getUnitName();
final BundleDescriptor bundle =
emfRef.getReferringBundleDescriptor();
PersistenceUnitDescriptor pu = bundle.findReferencedPU(unitName);
if(pu == null) {
throw new RuntimeException(localStrings.getLocalString(
"enterprise.deployment.exception-unresolved-pu-ref", "xxx", // NOI18N
new Object[] {emfRef.getName(),
bundle.getName()})
);
}
pus.add(pu);
}
return pus;
}
/**
* helper method: find all PUs referenced via @PersistenceContext or
* <persistence-context-ref>
*/
protected static Collection<? extends PersistenceUnitDescriptor>
findReferencedPUsViaPCRefs(JndiNameEnvironment component) {
Collection<PersistenceUnitDescriptor> pus =
new HashSet<PersistenceUnitDescriptor>();
for(EntityManagerReference emRef :
component.getEntityManagerReferenceDescriptors()) {
final String unitName = emRef.getUnitName();
final BundleDescriptor bundle =
emRef.getReferringBundleDescriptor();
PersistenceUnitDescriptor pu = bundle.findReferencedPU(unitName);
if(pu == null) {
throw new RuntimeException(localStrings.getLocalString(
"enterprise.deployment.exception-unresolved-pc-ref", "xxx", // NOI18N
new Object[] {emRef.getName(),
bundle.getName()})
);
}
if("RESOURCE_LOCAL".equals(pu.getTransactionType())) { // NOI18N
throw new RuntimeException(localStrings.getLocalString(
"enterprise.deployment.exception-non-jta-container-managed-em", "xxx", // NOI18N
new Object[] {emRef.getName(),
bundle.getName(),
pu.getName()})
);
}
pus.add(pu);
}
return pus;
}
/**
* It accepts both a quailified (e.g.) "lib/a.jar#FooPU" as well as
* unqualified name (e.g.) "FooPU". It then searched all the
* PersistenceUnits that are defined in the scope of this bundle
* descriptor to see which one matches the give name.
* @param unitName as used in @PersistenceUnit, @PersistenceContext
* <persistence-context-ref> or <persistence-unit-name>.
* If null, this method returns the default PU, if available.
* The reason it accepts null for default PU is because "" gets converted to
* null in EntityManagerReferenceHandler.processNewEmRefAnnotation.
* @return PersistenceUnitDescriptor that this unitName resolves to.
* Returns null, if unitName could not be resolved.
*/
public PersistenceUnitDescriptor findReferencedPU(String unitName) {
if(unitName == null || unitName.length()==0) { // uses default PU.
return findDefaultPU();
} else {
return findReferencedPU0(unitName);
}
}
/**
* This method is responsible for finding default persistence unit for
* a bundle descriptor.
* @return the default persistence unit for this bundle. returns null,
* if there isno PU defined or default can not be calculated because there
* are more than 1 PUs defined.
*/
public PersistenceUnitDescriptor findDefaultPU() {
// step #1: see if we have only one PU in the local scope.
PersistenceUnitDescriptor pu = null;
int totalNumberOfPUInBundle = 0;
for (PersistenceUnitsDescriptor nextPUs:
getPersistenceUnitsDescriptors()) {
for(PersistenceUnitDescriptor nextPU :
nextPUs.getPersistenceUnitDescriptors()) {
pu = nextPU;
totalNumberOfPUInBundle++;
}
}
if(totalNumberOfPUInBundle == 1) { // there is only one PU in this bundle.
return pu;
} else if(totalNumberOfPUInBundle == 0) { // there are no PUs in this bundle.
// step #2: see if we have only one PU in the ear.
int totalNumberOfPUInEar = 0;
for (PersistenceUnitsDescriptor nextPUs:
getApplication().getPersistenceUnitsDescriptors()) {
for(PersistenceUnitDescriptor nextPU :
nextPUs.getPersistenceUnitDescriptors()) {
pu = nextPU;
totalNumberOfPUInEar++;
}
}
if(totalNumberOfPUInEar == 1) {
return pu;
}
}
return null;
}
/**
* Internal method.
* This method is used to find referenced PU with a given name.
* It does not accept null or empty unit name.
* @param unitName
* @return
*/
private PersistenceUnitDescriptor findReferencedPU0(String unitName) {
int separatorIndex =
unitName.lastIndexOf(PERSISTENCE_UNIT_NAME_SEPARATOR);
if( separatorIndex != -1 ) { // qualified name
// uses # => must be defined in a utility jar at ear scope.
String unqualifiedUnitName =
unitName.substring(separatorIndex + 1);
String path = unitName.substring(0, separatorIndex);
// it' necessary to call getTargetUri as that takes care of
// converting ././b to canonical forms.
String puRoot = getTargetUri(this, path);
final PersistenceUnitsDescriptor pus =
getApplication().getPersistenceUnitsDescriptor(puRoot);
if(pus!=null) {
for(PersistenceUnitDescriptor pu :
pus.getPersistenceUnitDescriptors()) {
if(pu.getName().equals(unqualifiedUnitName)) {
return pu;
}
}
}
} else { // uses unqualified name.
// first look to see if there is a match with unqualified name,
// b'cos local scope takes precedence.
Map<String, PersistenceUnitDescriptor> visiblePUs =
getVisiblePUs();
PersistenceUnitDescriptor result = visiblePUs.get(unitName);
if(result != null) return result;
// next look to see if there is unique match in ear scope.
int sameNamedEarScopedPUCount = 0;
for(String s : visiblePUs.keySet()) {
int idx = s.lastIndexOf(PERSISTENCE_UNIT_NAME_SEPARATOR);
if(idx != -1 // ear scoped
&& s.substring(idx+1).matches(unitName)) {
result = visiblePUs.get(s);
sameNamedEarScopedPUCount++;
}
}
// if there are more than one ear scoped PU with same name (this
// is possible when PU is inside two different library jar),
// then user can not use unqualified name.
if(sameNamedEarScopedPUCount == 1) {
return result;
}
}
return null;
}
/**
* This method returns all the PUs that are defined in this bundle as well
* as the PUs defined in the ear level. e.g. for the following ear:
* ear/lib/a.jar#defines FooPU
* /lib/b.jar#defines FooPU
* ejb.jar#defines FooPU
* for the EjbBundleDescriptor (ejb.jar), the map will contain
* {(lib/a.jar#FooPU, PU1), (lib/b.jar#FooPU, PU2), (FooPU, PU3)}.
*
* @return a map of names to PUDescriptors that are visbible to this
* bundle descriptor. The name is a qualified name for ear scoped PUs
* where as it is in unqualified form for local PUs.
*/
public Map<String, PersistenceUnitDescriptor> getVisiblePUs() {
Map<String, PersistenceUnitDescriptor> result =
new HashMap<String, PersistenceUnitDescriptor>();
// local scoped PUs
for (PersistenceUnitsDescriptor pus :
getPersistenceUnitsDescriptors()) {
for(PersistenceUnitDescriptor pu :
pus.getPersistenceUnitDescriptors()) {
// for local PUs, use unqualified name.
result.put(pu.getName(), pu);
}
}
// ear scoped PUs
final Application application = getApplication();
if(application!=null) {
for(PersistenceUnitsDescriptor pus:
application.getPersistenceUnitsDescriptors()) {
for(PersistenceUnitDescriptor pu :
pus.getPersistenceUnitDescriptors()) {
// use fully qualified name for ear scoped PU
result.put(pu.getPuRoot()+ PERSISTENCE_UNIT_NAME_SEPARATOR + pu.getName(), pu);
}
}
}
return result;
}
/**
* Get the uri of a target based on a source module and a a relative uri
* from the perspective of that source module.
*
* @param origin bundle descriptor within an application
* @param relativeTargetUri relative uri from the given bundle
* descriptor
* @return target uri
*/
private String getTargetUri(BundleDescriptor origin,
String relativeTargetUri) {
try {
String archiveUri = origin.getModuleDescriptor().getArchiveUri();
return new URI(archiveUri).resolve(relativeTargetUri).getPath();
} catch (URISyntaxException use) {
throw new RuntimeException(use);
}
}
// return a short unique representation of this BundleDescriptor
public String getUniqueFriendlyId() {
String uniqueId;
// for standalone jars, return its registration name
// for applications, return the module uri
if (getApplication().isVirtual()) {
uniqueId = getApplication().getRegistrationName();
} else {
uniqueId = getModuleDescriptor().getArchiveUri();
}
return FileUtils.makeFriendlyFileName(uniqueId);
}
}