blob: 23648cc657cb622c97adb610fd7b77ec19fbe168 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.config;
import org.apache.openejb.JndiConstants;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.assembler.classic.ContainerInfo;
import org.apache.openejb.assembler.classic.ResourceInfo;
import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.jee.ActivationConfig;
import org.apache.openejb.jee.ActivationConfigProperty;
import org.apache.openejb.jee.AdminObject;
import org.apache.openejb.jee.AssemblyDescriptor;
import org.apache.openejb.jee.ConnectionDefinition;
import org.apache.openejb.jee.Connector;
import org.apache.openejb.jee.EnterpriseBean;
import org.apache.openejb.jee.InboundResourceadapter;
import org.apache.openejb.jee.InjectionTarget;
import org.apache.openejb.jee.JndiConsumer;
import org.apache.openejb.jee.JndiReference;
import org.apache.openejb.jee.MessageDestination;
import org.apache.openejb.jee.MessageDestinationRef;
import org.apache.openejb.jee.MessageDrivenBean;
import org.apache.openejb.jee.MessageListener;
import org.apache.openejb.jee.OutboundResourceAdapter;
import org.apache.openejb.jee.PersistenceContextRef;
import org.apache.openejb.jee.PersistenceRef;
import org.apache.openejb.jee.PersistenceType;
import org.apache.openejb.jee.ResourceAdapter;
import org.apache.openejb.jee.ResourceRef;
import org.apache.openejb.jee.SessionType;
import org.apache.openejb.jee.jpa.unit.Persistence;
import org.apache.openejb.jee.jpa.unit.PersistenceUnit;
import org.apache.openejb.jee.oejb3.EjbDeployment;
import org.apache.openejb.jee.oejb3.OpenejbJar;
import org.apache.openejb.jee.oejb3.ResourceLink;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.IntrospectionSupport;
import org.apache.openejb.util.LinkResolver;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.SuperProperties;
import org.apache.openejb.util.URISupport;
import org.apache.openejb.util.UniqueDefaultLinkResolver;
import javax.annotation.ManagedBean;
import javax.ejb.TimerService;
import javax.enterprise.inject.spi.BeanManager;
import javax.jms.Queue;
import javax.jms.Topic;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.ContextResolver;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import static java.util.Arrays.asList;
import static org.apache.openejb.config.ServiceUtils.ANY;
import static org.apache.openejb.config.ServiceUtils.NONE;
import static org.apache.openejb.config.ServiceUtils.hasServiceProvider;
import static org.apache.openejb.resource.jdbc.DataSourceFactory.trimNotSupportedDataSourceProperties;
import static org.apache.openejb.util.Join.join;
public class AutoConfig implements DynamicDeployer, JndiConstants {
public static final String ORIGIN_ANNOTATION = "Annotation";
public static final String ORIGIN_FLAG = "Origin";
public static Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, AutoConfig.class);
private static Set<String> ignoredReferenceTypes = new TreeSet<String>();
public static final String AUTOCREATE_JTA_DATASOURCE_FROM_NON_JTA_ONE_KEY = "openejb.autocreate.jta-datasource-from-non-jta-one";
public static final ThreadLocal<Collection<String>> PROVIDED_RESOURCES = new ThreadLocal<Collection<String>>();
public static final ThreadLocal<String> PROVIDED_RESOURCES_PREFIX = new ThreadLocal<String>();
static{
// Context objects are automatically handled
ignoredReferenceTypes.add("javax.ejb.SessionContext");
ignoredReferenceTypes.add("javax.ejb.EntityContext");
ignoredReferenceTypes.add("javax.ejb.MessageDrivenContext");
ignoredReferenceTypes.add("javax.ejb.EJBContext");
ignoredReferenceTypes.add("javax.xml.ws.WebServiceContext");
// URLs are automatically handled
ignoredReferenceTypes.add("java.net.URL");
// User transaction is automatically handled
ignoredReferenceTypes.add(UserTransaction.class.getName());
ignoredReferenceTypes.add(TransactionManager.class.getName());
ignoredReferenceTypes.add(TransactionSynchronizationRegistry.class.getName());
ignoredReferenceTypes.add(TimerService.class.getName());
// Bean Validation is automatically handled
ignoredReferenceTypes.add(Validator.class.getName());
ignoredReferenceTypes.add(ValidatorFactory.class.getName());
// CDI BeanManager is handled
ignoredReferenceTypes.add(BeanManager.class.getName());
// REST injections done via @Context and bound into a resource env...
ignoredReferenceTypes.add(Request.class.getName());
ignoredReferenceTypes.add(UriInfo.class.getName());
ignoredReferenceTypes.add(HttpHeaders.class.getName());
ignoredReferenceTypes.add(SecurityContext.class.getName());
ignoredReferenceTypes.add(ContextResolver.class.getName());
ignoredReferenceTypes.add(Application.class.getName());
}
private final ConfigurationFactory configFactory;
private boolean autoCreateContainers = true;
private boolean autoCreateResources = true;
public AutoConfig(ConfigurationFactory configFactory) {
this.configFactory = configFactory;
}
public synchronized boolean autoCreateResources() {
return autoCreateResources;
}
public synchronized void autoCreateResources(boolean autoCreateResources) {
this.autoCreateResources = autoCreateResources;
}
public synchronized boolean autoCreateContainers() {
return autoCreateContainers;
}
public synchronized void autoCreateContainers(boolean autoCreateContainers) {
this.autoCreateContainers = autoCreateContainers;
}
public void init() throws OpenEJBException {
}
public synchronized AppModule deploy(AppModule appModule) throws OpenEJBException {
AppResources appResources = new AppResources(appModule);
processDataSourceDefinitions(appModule);
for (EjbModule ejbModule : appModule.getEjbModules()) {
processActivationConfig(ejbModule);
}
resolveDestinationLinks(appModule);
resolvePersistenceRefs(appModule);
try {
for (EjbModule ejbModule : appModule.getEjbModules()) {
deploy(ejbModule, appResources);
}
for (ClientModule clientModule : appModule.getClientModules()) {
deploy(clientModule, appResources);
}
for (ConnectorModule connectorModule : appModule.getConnectorModules()) {
deploy(connectorModule);
}
for (WebModule webModule : appModule.getWebModules()) {
deploy(webModule, appResources);
}
for (PersistenceModule persistenceModule : appModule.getPersistenceModules()) {
deploy(appModule, persistenceModule);
}
} finally {
PROVIDED_RESOURCES.remove();
PROVIDED_RESOURCES_PREFIX.remove();
}
return appModule;
}
private void resolvePersistenceRefs(AppModule appModule) {
LinkResolver<PersistenceUnit> persistenceUnits = new UniqueDefaultLinkResolver<PersistenceUnit>();
for (PersistenceModule module : appModule.getPersistenceModules()) {
String rootUrl = module.getRootUrl();
for (PersistenceUnit unit : module.getPersistence().getPersistenceUnit()) {
unit.setId(unit.getName() + " " + rootUrl.hashCode());
persistenceUnits.add(rootUrl, unit.getName(), unit);
}
}
for (EjbModule ejbModule : appModule.getEjbModules()) {
URI moduleURI = ejbModule.getModuleUri();
for (JndiConsumer component : ejbModule.getEjbJar().getEnterpriseBeans()) {
processPersistenceRefs(component, ejbModule, persistenceUnits, moduleURI);
}
}
for (ClientModule clientModule : appModule.getClientModules()) {
URI moduleURI = URI.create(clientModule.getModuleId());
processPersistenceRefs(clientModule.getApplicationClient(), clientModule, persistenceUnits, moduleURI);
}
for (WebModule webModule : appModule.getWebModules()) {
URI moduleURI = URI.create(webModule.getModuleId());
processPersistenceRefs(webModule.getWebApp(), webModule, persistenceUnits, moduleURI);
}
}
private void processPersistenceRefs(JndiConsumer component, DeploymentModule module, LinkResolver<PersistenceUnit> persistenceUnits, URI moduleURI) {
String componentName = component.getJndiConsumerName();
ValidationContext validation = module.getValidation();
for (PersistenceRef ref : component.getPersistenceUnitRef()) {
processPersistenceRef(persistenceUnits, ref, moduleURI, componentName, validation);
}
for (PersistenceRef ref : component.getPersistenceContextRef()) {
processPersistenceRef(persistenceUnits, ref, moduleURI, componentName, validation);
}
}
private PersistenceUnit processPersistenceRef(LinkResolver<PersistenceUnit> persistenceUnits, PersistenceRef ref, URI moduleURI, String componentName, ValidationContext validation) {
if (ref.getMappedName() != null && ref.getMappedName().startsWith("jndi:")){
return null;
}
PersistenceUnit unit = persistenceUnits.resolveLink(ref.getPersistenceUnitName(), moduleURI);
// Explicitly check if we messed up the "if there's only one,
// that's what you get" rule by adding our "cmp" unit.
Collection<PersistenceUnit> cmpUnits = persistenceUnits.values("cmp");
if (unit == null && cmpUnits.size() > 0 && persistenceUnits.values().size() - cmpUnits.size() == 1) {
// We did, there is exactly one non-cmp unit. Let's find it.
for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
if (!persistenceUnit.getName().equals("cmp")){
// Found it
unit = persistenceUnit;
break;
}
}
}
// try again using the ref name
if (unit == null){
unit = persistenceUnits.resolveLink(ref.getName(), moduleURI);
}
// try again using the ref name with any prefix removed
if (unit == null){
String shortName = ref.getName().replaceFirst(".*/", "");
unit = persistenceUnits.resolveLink(shortName, moduleURI);
}
if (unit != null){
ref.setPersistenceUnitName(unit.getName());
ref.setMappedName(unit.getId());
} else {
// ----------------------------------------------
// Nothing was found. Let's try and figure out
// what went wrong and log a validation message
// ----------------------------------------------
String refType = "persistence";
if (ref instanceof PersistenceContextRef){
refType += "ContextRef";
} else refType += "UnitRef";
String refShortName = ref.getName();
if (refShortName.matches(".*\\..*/.*")){
refShortName = refShortName.replaceFirst(".*/", "");
}
List<String> availableUnits = new ArrayList<String>();
for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
availableUnits.add(persistenceUnit.getName());
}
Collections.sort(availableUnits);
String unitName = ref.getPersistenceUnitName();
if (availableUnits.size() == 0){
// Print a sample persistence.xml using their data
if (unitName == null){
unitName = refShortName;
}
validation.fail(componentName, refType + ".noPersistenceUnits", refShortName, unitName);
} else if ((ref.getPersistenceUnitName() == null || ref.getPersistenceUnitName().length()==0) && availableUnits.size() > 1) {
// Print a correct example of unitName in a ref
// DMB: Idea, the ability to set a default unit-name in openejb-jar.xml via a property
String sampleUnitName = availableUnits.get(0);
validation.fail(componentName, refType + ".noUnitName", refShortName, join(", ", availableUnits), sampleUnitName );
} else {
Collection<PersistenceUnit> vagueMatches = persistenceUnits.values(ref.getPersistenceUnitName());
if (vagueMatches.size() != 0) {
// Print the full rootUrls
List<String> possibleUnits = new ArrayList<String>();
for (PersistenceUnit persistenceUnit : persistenceUnits.values()) {
try {
URI unitURI = URI.create(persistenceUnit.getId());
unitURI = URISupport.relativize(moduleURI, unitURI);
possibleUnits.add(unitURI.toString());
} catch (Exception e) {
// id is typically not a valid URI
possibleUnits.add(persistenceUnit.getId());
}
}
Collections.sort(possibleUnits);
validation.fail(componentName, refType + ".vagueMatches", refShortName, unitName, possibleUnits.size(), join("\n", possibleUnits));
} else {
validation.fail(componentName, refType + ".noMatches", refShortName, unitName, join(", ", availableUnits));
}
}
}
return unit;
}
/**
* Set destination, destinationType, clientId and subscriptionName in the MDB activation config.
*/
private void processActivationConfig(EjbModule ejbModule) throws OpenEJBException {
OpenejbJar openejbJar;
if (ejbModule.getOpenejbJar() != null) {
openejbJar = ejbModule.getOpenejbJar();
} else {
openejbJar = new OpenejbJar();
ejbModule.setOpenejbJar(openejbJar);
}
Map<String, EjbDeployment> deployments = openejbJar.getDeploymentsByEjbName();
for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
if (bean instanceof MessageDrivenBean) {
MessageDrivenBean mdb = (MessageDrivenBean) bean;
if (mdb.getActivationConfig() == null) {
mdb.setActivationConfig(new ActivationConfig());
}
if (!isJms(mdb)) continue;
EjbDeployment ejbDeployment = deployments.get(bean.getEjbName());
if (ejbDeployment == null) {
throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
}
Properties properties = mdb.getActivationConfig().toProperties();
String destination = properties.getProperty("destinationName");
if (destination != null) {
mdb.getActivationConfig().addProperty("destination", destination);
// Remove destinationName as it is not in the standard ActivationSpec
List<ActivationConfigProperty> list = mdb.getActivationConfig().getActivationConfigProperty();
Iterator<ActivationConfigProperty> iterator = list.iterator();
while (iterator.hasNext()) {
ActivationConfigProperty configProperty = iterator.next();
if (configProperty.getActivationConfigPropertyName().equals("destinationName")){
iterator.remove();
break;
}
}
} else {
destination = properties.getProperty("destination");
}
// destination
// String destination = properties.getProperty("destination", properties.getProperty("destinationName"));
if (destination == null) {
destination = ejbDeployment.getDeploymentId();
mdb.getActivationConfig().addProperty("destination", destination);
}
// destination identifier
ResourceLink link = ejbDeployment.getResourceLink("openejb/destination");
if (link == null && mdb.getMessageDestinationLink() == null) {
link = new ResourceLink();
link.setResId(destination);
link.setResRefName("openejb/destination");
ejbDeployment.addResourceLink(link);
}
// destination type
String destinationType = properties.getProperty("destinationType");
if (destinationType == null && mdb.getMessageDestinationType() != null) {
destinationType = mdb.getMessageDestinationType();
mdb.getActivationConfig().addProperty("destinationType", destinationType);
}
if (mdb.getMessageDestinationType() == null) {
mdb.setMessageDestinationType(destinationType);
}
// topics need a clientId and subscriptionName
if ("javax.jms.Topic".equals(destinationType)) {
if (!properties.containsKey("clientId")) {
mdb.getActivationConfig().addProperty("clientId", ejbDeployment.getDeploymentId());
}
if (!properties.containsKey("subscriptionName")) {
mdb.getActivationConfig().addProperty("subscriptionName", ejbDeployment.getDeploymentId() + "_subscription");
}
}
}
}
}
private boolean isJms(MessageDrivenBean mdb) {
String messagingType = mdb.getMessagingType();
return (messagingType != null && messagingType.startsWith("javax.jms"));
}
/**
* Set resource id in all message-destination-refs and MDBs that are using message destination links.
*/
private void resolveDestinationLinks(AppModule appModule) throws OpenEJBException {
// build up a link resolver
LinkResolver<MessageDestination> destinationResolver = new LinkResolver<MessageDestination>();
for (EjbModule ejbModule : appModule.getEjbModules()) {
AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
if (assembly != null) {
for (MessageDestination destination : assembly.getMessageDestination()) {
destinationResolver.add(ejbModule.getModuleUri(), destination.getMessageDestinationName(), destination);
}
}
}
for (ClientModule clientModule : appModule.getClientModules()) {
for (MessageDestination destination : clientModule.getApplicationClient().getMessageDestination()) {
destinationResolver.add(appModule.getModuleUri(), destination.getMessageDestinationName(), destination);
}
}
for (WebModule webModule : appModule.getWebModules()) {
for (MessageDestination destination : webModule.getWebApp().getMessageDestination()) {
destinationResolver.add(appModule.getModuleUri(), destination.getMessageDestinationName(), destination);
}
}
// remember the type of each destination so we can use it to fillin MDBs that don't declare destination type
Map<MessageDestination,String> destinationTypes = new HashMap<MessageDestination,String>();
// resolve all MDBs with destination links
// if MessageDestination does not have a mapped name assigned, give it the destination from the MDB
for (EjbModule ejbModule : appModule.getEjbModules()) {
AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
if (assembly == null) {
continue;
}
URI moduleUri = ejbModule.getModuleUri();
OpenejbJar openejbJar = ejbModule.getOpenejbJar();
for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
// MDB destination is deploymentId if none set
if (bean instanceof MessageDrivenBean) {
MessageDrivenBean mdb = (MessageDrivenBean) bean;
EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName());
if (ejbDeployment == null) {
throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
}
// skip destination refs without a destination link
String link = mdb.getMessageDestinationLink();
if (link == null || link.length() == 0) {
continue;
}
// resolve the destination... if we don't find one it is a configuration bug
MessageDestination destination = destinationResolver.resolveLink(link, moduleUri);
if (destination == null) {
throw new OpenEJBException("Message destination " + link + " for message driven bean " + mdb.getEjbName() + " not found");
}
// get the destinationId is the mapped name
String destinationId = destination.getMappedName();
if (destinationId == null) {
// if we don't have a mapped name use the destination of the mdb
Properties properties = mdb.getActivationConfig().toProperties();
destinationId = properties.getProperty("destination");
destination.setMappedName(destinationId);
}
if (mdb.getMessageDestinationType() != null && !destinationTypes.containsKey(destination)) {
destinationTypes.put(destination, mdb.getMessageDestinationType());
}
// destination identifier
ResourceLink resourceLink = ejbDeployment.getResourceLink("openejb/destination");
if (resourceLink == null) {
resourceLink = new ResourceLink();
resourceLink.setResRefName("openejb/destination");
ejbDeployment.addResourceLink(resourceLink);
}
resourceLink.setResId(destinationId);
}
}
}
// resolve all message destination refs with links and assign a ref id to the reference
for (EjbModule ejbModule : appModule.getEjbModules()) {
AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
if (assembly == null) {
continue;
}
URI moduleUri = ejbModule.getModuleUri();
OpenejbJar openejbJar = ejbModule.getOpenejbJar();
for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName());
if (ejbDeployment == null) {
throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
}
for (MessageDestinationRef ref : bean.getMessageDestinationRef()) {
// skip destination refs with a resource link already assigned
if (ref.getMappedName() == null && ejbDeployment.getResourceLink(ref.getName()) == null) {
String destinationId = resolveDestinationId(ref, moduleUri, destinationResolver, destinationTypes);
if (destinationId != null) {
// build the link and add it
ResourceLink resourceLink = new ResourceLink();
resourceLink.setResId(destinationId);
resourceLink.setResRefName(ref.getName());
ejbDeployment.addResourceLink(resourceLink);
}
}
}
}
}
for (ClientModule clientModule : appModule.getClientModules()) {
URI moduleUri = clientModule.getModuleUri();
for (MessageDestinationRef ref : clientModule.getApplicationClient().getMessageDestinationRef()) {
String destinationId = resolveDestinationId(ref, moduleUri, destinationResolver, destinationTypes);
if (destinationId != null) {
// for client modules we put the destinationId in the mapped name
ref.setMappedName(destinationId);
}
}
}
for (WebModule webModule : appModule.getWebModules()) {
URI moduleUri = URI.create(webModule.getModuleId());
for (MessageDestinationRef ref : webModule.getWebApp().getMessageDestinationRef()) {
String destinationId = resolveDestinationId(ref, moduleUri, destinationResolver, destinationTypes);
if (destinationId != null) {
// for web modules we put the destinationId in the mapped name
ref.setMappedName(destinationId);
}
}
}
// Process MDBs one more time...
// this time fill in the destination type (if not alreday specified) with
// the info from the destination (which got filled in from the references)
for (EjbModule ejbModule : appModule.getEjbModules()) {
AssemblyDescriptor assembly = ejbModule.getEjbJar().getAssemblyDescriptor();
if (assembly == null) {
continue;
}
URI moduleUri = URI.create(ejbModule.getModuleId());
OpenejbJar openejbJar = ejbModule.getOpenejbJar();
for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
// MDB destination is deploymentId if none set
if (bean instanceof MessageDrivenBean) {
MessageDrivenBean mdb = (MessageDrivenBean) bean;
if (!isJms(mdb)) continue;
EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName());
if (ejbDeployment == null) {
throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
}
// if destination type is already set in, continue
String destinationType = mdb.getMessageDestinationType();
if (destinationType != null) {
continue;
}
String link = mdb.getMessageDestinationLink();
if (link != null && link.length() != 0) {
// resolve the destination... if we don't find one it is a configuration bug
MessageDestination destination = destinationResolver.resolveLink(link, moduleUri);
if (destination == null) {
throw new OpenEJBException("Message destination " + link + " for message driven bean " + mdb.getEjbName() + " not found");
}
destinationType = destinationTypes.get(destination);
}
if (destinationType == null) {
// couldn't determine type... we'll have to guess
// if destination name contains the string "queue" or "topic" we use that
Properties properties = mdb.getActivationConfig().toProperties();
String destination = properties.getProperty("destination").toLowerCase();
if (destination.indexOf("queue") >= 0) {
destinationType = Queue.class.getName();
} else if (destination.indexOf("topic") >= 0) {
destinationType = Topic.class.getName();
} else {
// Queue is the default
destinationType = Queue.class.getName();
}
logger.info("Auto-configuring a message driven bean " + ejbDeployment.getDeploymentId() + " destination " + properties.getProperty("destination") + " to be destinationType " + destinationType);
}
if (destinationType != null) {
mdb.getActivationConfig().addProperty("destinationType", destinationType);
mdb.setMessageDestinationType(destinationType);
// topics need a clientId and subscriptionName
if ("javax.jms.Topic".equals(destinationType)) {
Properties properties = mdb.getActivationConfig().toProperties();
if (!properties.containsKey("clientId")) {
mdb.getActivationConfig().addProperty("clientId", ejbDeployment.getDeploymentId());
}
if (!properties.containsKey("subscriptionName")) {
mdb.getActivationConfig().addProperty("subscriptionName", ejbDeployment.getDeploymentId() + "_subscription");
}
}
}
}
}
}
}
private String resolveDestinationId(MessageDestinationRef ref, URI moduleUri, LinkResolver<MessageDestination> destinationResolver, Map<MessageDestination,String> destinationTypes) throws OpenEJBException {
// skip destination refs without a destination link
String link = ref.getMessageDestinationLink();
if (link == null || link.length() == 0) {
return null;
}
// resolve the destination... if we don't find one it is a configuration bug
MessageDestination destination = destinationResolver.resolveLink(link, moduleUri);
if (destination == null) {
throw new OpenEJBException("Message destination " + link + " for message-destination-ref " + ref.getMessageDestinationRefName() + " not found");
}
// remember the type of each destination so we can use it to fillin MDBs that don't declare destination type
if (ref.getMessageDestinationType() != null && !destinationTypes.containsKey(destination)) {
destinationTypes.put(destination, ref.getMessageDestinationType());
}
// get the destinationId
String destinationId = destination.getMappedName();
if (destinationId == null) destination.getMessageDestinationName();
return destinationId;
}
private void deploy(ClientModule clientModule, AppResources appResources) throws OpenEJBException {
processJndiRefs(clientModule.getModuleId(), clientModule.getApplicationClient(), appResources, clientModule.getClassLoader());
}
@SuppressWarnings({"UnusedDeclaration"})
private void deploy(ConnectorModule connectorModule) throws OpenEJBException {
// Nothing to process for resource modules
}
private void deploy(WebModule webModule, AppResources appResources) throws OpenEJBException {
processJndiRefs(webModule.getModuleId(), webModule.getWebApp(), appResources, webModule.getClassLoader());
}
private void processJndiRefs(String moduleId, JndiConsumer jndiConsumer, AppResources appResources, ClassLoader classLoader) throws OpenEJBException {
final Collection<String> ignoredResources = PROVIDED_RESOURCES.get();
String ignoredResourcesPrefix = PROVIDED_RESOURCES_PREFIX.get();
if (ignoredResourcesPrefix == null) {
ignoredResourcesPrefix = "";
}
// Resource reference
for (ResourceRef ref : jndiConsumer.getResourceRef()) {
// skip destinations with lookup name
if (ref.getLookupName() != null) {
continue;
}
// skip destinations with a global jndi name
String mappedName = (ref.getMappedName() == null) ? "": ref.getMappedName();
if (mappedName.startsWith("jndi:")) {
continue;
}
String refType = getType(ref, classLoader);
// skip references such as URLs which are automatically handled by the server
if (isIgnoredReferenceType(refType, classLoader)) {
continue;
}
//skips references such as javax.ws.rs.core.Context
if (isWSSpecificReferenceType(classLoader, ref)) {
continue;
}
String destinationId = (mappedName.length() == 0) ? ref.getName() : mappedName;
if (ignoredResources != null && ignoredResources.contains(destinationId)) {
ref.setLookupName(ignoredResourcesPrefix + destinationId);
ref.setName("openejb/" + moduleId + "/" + destinationId);
} else {
try {
destinationId = getResourceId(moduleId, destinationId, refType, appResources);
} catch (OpenEJBException ex) {
if (!(ref instanceof ContextRef)) {
throw ex;
} else { // let jaxrs provider manage it
continue;
}
}
ref.setMappedName(destinationId);
}
}
// Resource env reference
for (JndiReference ref : jndiConsumer.getResourceEnvRef()) {
// skip destinations with lookup name
if (ref.getLookupName() != null) {
continue;
}
// skip destinations with a global jndi name
String mappedName = (ref.getMappedName() == null) ? "": ref.getMappedName();
if (mappedName.startsWith("jndi:")) {
continue;
}
String refType = getType(ref, classLoader);
// skip references such as URLs which are automatically handled by the server
if (isIgnoredReferenceType(refType, classLoader)) {
continue;
}
String destinationId = (mappedName.length() == 0) ? ref.getName() : mappedName;
destinationId = getResourceEnvId(moduleId, destinationId, refType, appResources);
ref.setMappedName(destinationId);
}
// Message destination reference
for (MessageDestinationRef ref : jndiConsumer.getMessageDestinationRef()) {
// skip destinations with lookup name
if (ref.getLookupName() != null) {
continue;
}
// skip destinations with a global jndi name
String mappedName = (ref.getMappedName() == null) ? "": ref.getMappedName();
if (mappedName.startsWith("jndi:")) {
continue;
}
String destinationId = (mappedName.length() == 0) ? ref.getName() : mappedName;
destinationId = getResourceEnvId(moduleId, destinationId, ref.getType(), appResources);
ref.setMappedName(destinationId);
}
}
private boolean isWSSpecificReferenceType(ClassLoader classLoader, ResourceRef ref) {
try {
if (ref.getInjectionTarget().size() > 0) {
InjectionTarget target = ref.getInjectionTarget().iterator().next();
String targetClassString = target.getInjectionTargetClass();
String targetNameString = target.getInjectionTargetName();
Class targetClass = classLoader.loadClass(targetClassString);
Field targetField = targetClass.getDeclaredField(targetNameString);
if (targetField.getAnnotation(Context.class) != null) {
System.out.println("Ignored javax.ws.rs.core.Context JNDI Resource for field '"+targetNameString+"' in type '"+targetClassString+"'");
return true;
}
}
} catch (Exception e) {}
return false;
}
private boolean isIgnoredReferenceType(String typeName, ClassLoader loader) {
if (ignoredReferenceTypes.contains(typeName)) {
return true;
} else if (loader != null) {
try {
Class<?> type = loader.loadClass(typeName);
return type.isAnnotationPresent(ManagedBean.class);
} catch (ClassNotFoundException e) {
// ignore
}
}
return false;
}
private void deploy(EjbModule ejbModule, AppResources appResources) throws OpenEJBException {
OpenejbJar openejbJar;
if (ejbModule.getOpenejbJar() != null) {
openejbJar = ejbModule.getOpenejbJar();
} else {
openejbJar = new OpenejbJar();
ejbModule.setOpenejbJar(openejbJar);
}
Map<String, EjbDeployment> deployments = openejbJar.getDeploymentsByEjbName();
for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) {
EjbDeployment ejbDeployment = deployments.get(bean.getEjbName());
if (ejbDeployment == null) {
throw new OpenEJBException("No ejb deployment found for ejb " + bean.getEjbName());
}
Class<? extends ContainerInfo> containerInfoType = ConfigurationFactory.getContainerInfoType(getType(bean));
if (ejbDeployment.getContainerId() == null && !skipMdb(bean)) {
String containerId = getUsableContainer(containerInfoType, bean, appResources);
if (containerId == null){
containerId = createContainer(containerInfoType, ejbDeployment, bean);
}
ejbDeployment.setContainerId(containerId);
}
// create the container if it doesn't exist
List<String> containerIds = configFactory.getContainerIds();
containerIds.addAll(appResources.getContainerIds());
if (!containerIds.contains(ejbDeployment.getContainerId()) && !skipMdb(bean)) {
createContainer(containerInfoType, ejbDeployment, bean);
}
// Resource reference
for (ResourceRef ref : bean.getResourceRef()) {
processResourceRef(ref, ejbDeployment, appResources, ejbModule.getClassLoader());
}
// Resource env reference
for (JndiReference ref : bean.getResourceEnvRef()) {
processResourceEnvRef(ref, ejbDeployment, appResources, ejbModule.getClassLoader());
}
// Message destination reference
for (MessageDestinationRef ref : bean.getMessageDestinationRef()) {
processResourceEnvRef(ref, ejbDeployment, appResources, ejbModule.getClassLoader());
}
// mdb message destination id
if (autoCreateResources && bean instanceof MessageDrivenBean) {
MessageDrivenBean mdb = (MessageDrivenBean) bean;
ResourceLink resourceLink = ejbDeployment.getResourceLink("openejb/destination");
if (resourceLink != null) {
try {
String destinationId = getResourceEnvId(bean.getEjbName(), resourceLink.getResId(), mdb.getMessageDestinationType(), appResources);
resourceLink.setResId(destinationId);
} catch (OpenEJBException e) {
// The MDB doesn't need the auto configured "openejb/destination" env entry
ejbDeployment.removeResourceLink("openejb/destination");
}
}
}
}
}
private void processDataSourceDefinitions(AppModule module) throws OpenEJBException {
Collection<Resource> resources = module.getResources();
if (resources.size() == 0) return;
List<JndiConsumer> jndiConsumers = new ArrayList<JndiConsumer>();
for (WebModule webModule : module.getWebModules()) {
final JndiConsumer consumer = webModule.getWebApp();
jndiConsumers.add(consumer);
}
for (EjbModule ejbModule : module.getEjbModules()) {
Collections.addAll(jndiConsumers, ejbModule.getEjbJar().getEnterpriseBeans());
}
for (Resource resource : resources) {
Properties properties = resource.getProperties();
if (DataSource.class.getName().equals(resource.getType())
|| DataSource.class.getSimpleName().equals(resource.getType())) {
trimNotSupportedDataSourceProperties(properties);
}
ResourceInfo resourceInfo = configFactory.configureService(resource, ResourceInfo.class);
final ResourceRef resourceRef = new ResourceRef();
resourceRef.setResType(resource.getType());
if (DataSource.class.getName().equals(resource.getType())
&& resource.getProperties().containsKey(ORIGIN_FLAG)
&& resource.getProperties().getProperty(ORIGIN_FLAG).equals(ORIGIN_ANNOTATION)) {
properties.remove(ORIGIN_FLAG);
resourceInfo.id = module.getModuleId() + "/" + resourceInfo.id;
if (properties.get("JdbcUrl") == null) {
final String url = getVendorUrl(properties);
if (url != null) {
properties.put("JdbcUrl", url);
}
}
resourceRef.setResRefName(dataSourceLookupName(resource));
} else {
resourceRef.setResRefName(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id);
}
resourceRef.setMappedName(resourceInfo.id);
for (JndiConsumer consumer : jndiConsumers) {
final ResourceRef existing = consumer.getResourceRefMap().get(resourceRef.getKey());
if (existing != null) {
existing.setMappedName(resourceRef.getMappedName());
} else {
consumer.getResourceRef().add(resourceRef);
}
}
installResource(module.getModuleId(), resourceInfo);
}
resources.clear();
}
private String dataSourceLookupName(Resource datasource) {
final String jndi = datasource.getJndi();
if (jndi.startsWith("java:")) return jndi;
if (jndi.startsWith("comp/env/")) return "java:" + jndi;
if (jndi.startsWith("module/")) return "java:" + jndi;
if (jndi.startsWith("global/")) return "java:" + jndi;
if (jndi.startsWith("app/")) return "java:" + jndi;
return "java:comp/env/" + jndi;
}
private static String getVendorUrl(Properties properties) {
final String driver = properties.getProperty("JdbcDriver");
final String serverName = properties.getProperty("ServerName");
final int port = getInt(properties.get("PortNumber"));
final boolean remote = port != -1;
final String databaseName = properties.getProperty("DatabaseName");
if (driver == null || driver.equals("org.hsqldb.jdbcDriver")) {
if (remote) {
return String.format("jdbc:hsqldb:hsql://%s:%s/%s", serverName, port, databaseName);
} else {
return String.format("jdbc:hsqldb:mem:%s", databaseName);
}
}
if (driver.equals("org.apache.derby.jdbc.EmbeddedDriver")) {
return String.format("jdbc:derby:%s;create=true", databaseName);
}
if (driver.equals("org.apache.derby.jdbc.ClientDriver")) {
return String.format("jdbc:derby://%s:%s/%s;create=true", serverName, port, databaseName);
}
if (driver.equals("com.mysql.jdbc.Driver")) {
return String.format("jdbc:mysql://%s:%s/%s", serverName, port, databaseName);
}
if (driver.equals("com.postgresql.jdbc.Driver")) {
return String.format("jdbc:postgresql://%s:%s/%s", serverName, port, databaseName);
}
if (driver.equals("oracle.jdbc.OracleDriver")) {
return String.format("jdbc:oracle:thin:@//%s:%s/%s", serverName, port, databaseName);
}
return null;
}
private static int getInt(Object number) {
try {
return (Integer) number;
} catch (Exception e) {
try {
return Integer.parseInt(number+"");
} catch (NumberFormatException e1) {
return -1;
}
}
}
private void set(Properties properties, String key, String value) {
if (value == null || value.length() == 0) return;
properties.put(key, value);
}
private void set(Properties properties, String key, int value) {
set(properties, key, value, 0);
}
private void set(Properties properties, String key, int value, int min) {
if (value < min) return;
properties.put(key, value);
}
private String createContainer(Class<? extends ContainerInfo> containerInfoType, EjbDeployment ejbDeployment, EnterpriseBean bean) throws OpenEJBException {
if (!autoCreateContainers) {
throw new OpenEJBException("A container of type " + getType(bean) + " must be declared in the configuration file for bean: " + bean.getEjbName());
}
// get the container info (data used to build the container)
ContainerInfo containerInfo = configFactory.configureService(containerInfoType);
logger.info("Auto-creating a container for bean " + ejbDeployment.getDeploymentId() + ": Container(type=" + getType(bean) + ", id=" + containerInfo.id + ")");
// if the is an MDB container we need to resolve the resource adapter
String resourceAdapterId = containerInfo.properties.getProperty("ResourceAdapter");
if (resourceAdapterId != null) {
String newResourceId = getResourceId(ejbDeployment.getDeploymentId(), resourceAdapterId, null, null);
if (resourceAdapterId != newResourceId) {
containerInfo.properties.setProperty("ResourceAdapter", newResourceId);
}
}
// install the container
configFactory.install(containerInfo);
return containerInfo.id;
}
private void processResourceRef(ResourceRef ref,
EjbDeployment ejbDeployment,
AppResources appResources,
ClassLoader classLoader) throws OpenEJBException {
final Collection<String> ignoredResources = PROVIDED_RESOURCES.get();
String ignoredResourcesPrefix = PROVIDED_RESOURCES_PREFIX.get();
if (ignoredResourcesPrefix == null) {
ignoredResourcesPrefix = "";
}
// skip destinations with lookup name
if (ref.getLookupName() != null) {
return;
}
// skip destinations with a global jndi name
String mappedName = (ref.getMappedName() == null) ? "": ref.getMappedName();
if (mappedName.startsWith("jndi:")) {
return;
}
String refName = ref.getName();
String refType = getType(ref, classLoader);
// skip references such as URLs which are automatically handled by the server
if (ignoredReferenceTypes.contains(refType)) {
return;
}
try {
final Class<?> clazz = classLoader.loadClass(refType);
if (clazz.isAnnotationPresent(ManagedBean.class)) {
return;
}
} catch (Throwable t) {
}
ResourceLink link = ejbDeployment.getResourceLink(refName);
if (link == null) {
String id = (mappedName.length() == 0) ? ref.getName() : mappedName;
if (ignoredResources != null && (ignoredResources.contains(id) || ignoredResources.contains(correctedId(ignoredResourcesPrefix, id)))) {
final String correctedId = ignoredResourcesPrefix + correctedId(ignoredResourcesPrefix, id);
ref.setLookupName(correctedId);
ref.setName(correctedId);
return;
}
id = getResourceId(ejbDeployment.getDeploymentId(), id, refType, appResources);
logger.info("Auto-linking resource-ref '" + refName + "' in bean " + ejbDeployment.getDeploymentId() + " to Resource(id=" + id + ")");
link = new ResourceLink();
link.setResId(id);
link.setResRefName(refName);
ejbDeployment.addResourceLink(link);
} else {
String id = getResourceId(ejbDeployment.getDeploymentId(), link.getResId(), refType, appResources);
link.setResId(id);
link.setResRefName(refName);
}
}
private static String correctedId(final String ignoredResourcesPrefix, final String id) {
String newId = id;
String ignoredId = ignoredResourcesPrefix;
// first unify beginning of the jndi name (we can get this / after java:)
if (newId.startsWith("java:/")) {
newId = "java:" + newId.substring("java:/".length());
}
if (ignoredResourcesPrefix.startsWith("java:/")) {
ignoredId = "java:" + ignoredResourcesPrefix.substring("java:/".length());
}
// remove prefix if necessary
if (newId.startsWith(ignoredId)) {
return newId.substring(ignoredId.length());
}
return newId;
}
private void processResourceEnvRef(JndiReference ref,
EjbDeployment ejbDeployment,
AppResources appResources,
ClassLoader classLoader) throws OpenEJBException {
// skip destinations with lookup name
if (ref.getLookupName() != null) {
return;
}
// skip destinations with a global jndi name
String mappedName = (ref.getMappedName() == null) ? "": ref.getMappedName();
if (mappedName.startsWith("jndi:")) {
return;
}
String refName = ref.getName();
String refType = getType(ref, classLoader);
// skip references such as SessionContext which are automatically handled by the server
if (isIgnoredReferenceType(refType, classLoader)) {
return;
}
ResourceLink link = ejbDeployment.getResourceLink(refName);
if (link == null) {
String id = (mappedName.length() == 0) ? refName : mappedName;
id = getResourceEnvId(ejbDeployment.getDeploymentId(), id, refType, appResources);
if (id == null) {
// could be a session context ref
return;
}
logger.info("Auto-linking resource-env-ref '" + refName + "' in bean " + ejbDeployment.getDeploymentId() + " to Resource(id=" + id + ")");
link = new ResourceLink();
link.setResId(id);
link.setResRefName(refName);
ejbDeployment.addResourceLink(link);
} else {
String id = getResourceEnvId(ejbDeployment.getDeploymentId(), link.getResId(), refType, appResources);
link.setResId(id);
link.setResRefName(refName);
}
}
private String getType(JndiReference ref, ClassLoader classLoader) throws OpenEJBException {
if (ref.getType() != null) {
return ref.getType();
}
if (classLoader != null) {
Set<InjectionTarget> injections = ref.getInjectionTarget();
for (InjectionTarget injection : injections) {
try {
Class target = classLoader.loadClass(injection.getInjectionTargetClass().trim());
Class type = IntrospectionSupport.getPropertyType(target, injection.getInjectionTargetName().trim());
return type.getName();
} catch (ClassNotFoundException e) {
// ignore
} catch (NoSuchFieldException e) {
// ignore
}
}
}
throw new OpenEJBException("Unable to infer type for " + ref.getKey());
}
private static boolean skipMdb(Object bean) {
return bean instanceof MessageDrivenBean && SystemInstance.get().hasProperty("openejb.geronimo");
}
private static String getType(EnterpriseBean enterpriseBean) throws OpenEJBException {
if (enterpriseBean instanceof org.apache.openejb.jee.EntityBean) {
if (((org.apache.openejb.jee.EntityBean)enterpriseBean).getPersistenceType() == PersistenceType.CONTAINER) {
return BeanTypes.CMP_ENTITY;
} else {
return BeanTypes.BMP_ENTITY;
}
} else if (enterpriseBean instanceof org.apache.openejb.jee.SessionBean) {
if (((org.apache.openejb.jee.SessionBean) enterpriseBean).getSessionType() == SessionType.STATEFUL) {
return BeanTypes.STATEFUL;
} else if (((org.apache.openejb.jee.SessionBean) enterpriseBean).getSessionType() == SessionType.SINGLETON) {
return BeanTypes.SINGLETON;
} else if (((org.apache.openejb.jee.SessionBean) enterpriseBean).getSessionType() == SessionType.MANAGED) {
return BeanTypes.MANAGED;
} else {
return BeanTypes.STATELESS;
}
} else if (enterpriseBean instanceof org.apache.openejb.jee.MessageDrivenBean) {
return BeanTypes.MESSAGE;
}
throw new OpenEJBException("Unknown enterprise bean type " + enterpriseBean.getClass().getName());
}
private void deploy(AppModule app, PersistenceModule persistenceModule) throws OpenEJBException {
if (!autoCreateResources) {
return;
}
Persistence persistence = persistenceModule.getPersistence();
for (PersistenceUnit unit : persistence.getPersistenceUnit()) {
if (unit.getProvider() != null){
logger.info("Configuring PersistenceUnit(name="+unit.getName()+", provider="+unit.getProvider()+")");
} else {
logger.info("Configuring PersistenceUnit(name="+unit.getName()+")");
}
Properties required = new Properties();
// if (unit.getJtaDataSource() == null && unit.getNonJtaDataSource() == null){
// unit.setJtaDataSource("JtaDataSource");
// unit.setNonJtaDataSource("NonJtaDataSource");
// } else if (unit.getJtaDataSource() == null){
// unit.setJtaDataSource(unit.getNonJtaDataSource()+"Jta");
// } else if (unit.getNonJtaDataSource() == null){
// unit.setNonJtaDataSource(unit.getJtaDataSource()+"NonJta");
// }
logger.debug("raw <jta-data-source>" + unit.getJtaDataSource() + "</jta-datasource>");
logger.debug("raw <non-jta-data-source>" + unit.getNonJtaDataSource() + "</non-jta-datasource>");
unit.setJtaDataSource(normalizeResourceId(unit.getJtaDataSource()));
unit.setNonJtaDataSource(normalizeResourceId(unit.getNonJtaDataSource()));
logger.debug("normalized <jta-data-source>" + unit.getJtaDataSource() + "</jta-datasource>");
logger.debug("normalized <non-jta-data-source>" + unit.getNonJtaDataSource() + "</non-jta-datasource>");
if (logger.isDebugEnabled()){
required.put("JtaManaged", "true");
List<String> managed = configFactory.getResourceIds("DataSource", required);
required.put("JtaManaged", "false");
List<String> unmanaged = configFactory.getResourceIds("DataSource", required);
required.clear();
List<String> unknown = configFactory.getResourceIds("DataSource", required);
logger.debug("Available DataSources");
for (String name : managed) {
logger.debug("DataSource(name=" + name + ", JtaManaged=true)");
}
for (String name : unmanaged) {
logger.debug("DataSource(name=" + name + ", JtaManaged=false)");
}
for (String name : unknown) {
if (managed.contains(name)) continue;
if (unmanaged.contains(name)) continue;
logger.debug("DataSource(name=" + name + ", JtaManaged=<unknown>)");
}
}
required.put("JtaManaged", "true");
String jtaDataSourceId = findResourceId(unit.getJtaDataSource(), "DataSource", required, null);
required.put("JtaManaged", "false");
String nonJtaDataSourceId = findResourceId(unit.getNonJtaDataSource(), "DataSource", required, null);
if (jtaDataSourceId != null && nonJtaDataSourceId != null){
// Both DataSources were explicitly configured.
setJtaDataSource(unit, jtaDataSourceId);
setNonJtaDataSource(unit, nonJtaDataSourceId);
continue;
}
//
// If the jta-data-source or the non-jta-data-source link to
// third party resources, then we can't do any auto config
// for them. We give them what they asked for and move on.
//
if (jtaDataSourceId == null && nonJtaDataSourceId == null) {
required.put("JtaManaged", NONE);
jtaDataSourceId = findResourceId(unit.getJtaDataSource(), "DataSource", required, null);
nonJtaDataSourceId = findResourceId(unit.getNonJtaDataSource(), "DataSource", required, null);
if (jtaDataSourceId != null || nonJtaDataSourceId != null) {
if (jtaDataSourceId != null) setJtaDataSource(unit, jtaDataSourceId);
if (nonJtaDataSourceId != null) setNonJtaDataSource(unit, nonJtaDataSourceId);
continue;
}
}
// We are done with the most optimal configuration.
//
// If both the jta-data-source and non-jta-data-source
// references were explicitly and correctly configured
// to existing datasource, we wouldn't get this far.
//
// At this point we see if either we can't figure out
// if there's an issue with their configuration or
// if we can't intelligently complete their configuration.
//
// Do both the jta-data-source and non-jta-data-source references
// point to the same datasource?
//
// If so, then unlink the invalid one so defaulting rules can
// possibly fill in a good value.
//
required.put("JtaManaged", ANY);
String possibleJta = findResourceId(unit.getJtaDataSource(), "DataSource", required, null);
String possibleNonJta = findResourceId(unit.getNonJtaDataSource(), "DataSource", required, null);
if (possibleJta != null && possibleJta == possibleNonJta){
ResourceInfo dataSource = configFactory.getResourceInfo(possibleJta);
String jtaManaged = (String) dataSource.properties.get("JtaManaged");
logger.warning("PeristenceUnit(name=" + unit.getName() + ") invalidly refers to Resource(id=" + dataSource.id + ") as both its <jta-data-source> and <non-jta-data-source>.");
if ("true".equalsIgnoreCase(jtaManaged)){
nonJtaDataSourceId = null;
unit.setNonJtaDataSource(null);
} else if ("false".equalsIgnoreCase(jtaManaged)){
jtaDataSourceId = null;
unit.setJtaDataSource(null);
}
}
//
// Do the jta-data-source and non-jta-data-source references
// point to innapropriately configured Resources?
//
checkUnitDataSourceRefs(unit);
//
// Do either the jta-data-source and non-jta-data-source
// references point to the explicit name of a ServiceProvider?
//
if (jtaDataSourceId == null && nonJtaDataSourceId == null){
jtaDataSourceId = findResourceProviderId(unit.getJtaDataSource());
nonJtaDataSourceId = findResourceProviderId(unit.getNonJtaDataSource());
// if one of them is not null we have a match on at least one
// we can just create the second resource using the first as a template
if (jtaDataSourceId != null || nonJtaDataSourceId != null){
Resource jtaResource = new Resource(jtaDataSourceId, "DataSource", jtaDataSourceId);
jtaResource.getProperties().setProperty("JtaManaged", "true");
Resource nonJtaResource = new Resource(nonJtaDataSourceId, "DataSource", nonJtaDataSourceId);
nonJtaResource.getProperties().setProperty("JtaManaged", "false");
if (jtaDataSourceId == null){
jtaResource.setId(nonJtaDataSourceId+"Jta");
jtaResource.setProvider(nonJtaDataSourceId);
} else if (nonJtaDataSourceId == null){
nonJtaResource.setId(jtaDataSourceId+"NonJta");
nonJtaResource.setProvider(jtaDataSourceId);
}
ResourceInfo jtaResourceInfo = configFactory.configureService(jtaResource, ResourceInfo.class);
ResourceInfo nonJtaResourceInfo = configFactory.configureService(nonJtaResource, ResourceInfo.class);
logAutoCreateResource(jtaResourceInfo, "DataSource", unit.getName());
jtaDataSourceId = installResource(unit.getName(), jtaResourceInfo);
logAutoCreateResource(nonJtaResourceInfo, "DataSource", unit.getName());
nonJtaDataSourceId = installResource(unit.getName(), nonJtaResourceInfo);
setJtaDataSource(unit, jtaDataSourceId);
setNonJtaDataSource(unit, nonJtaDataSourceId);
continue;
}
}
// No data sources were specified:
// Look for defaults, see https://issues.apache.org/jira/browse/OPENEJB-1027
if (jtaDataSourceId == null && nonJtaDataSourceId == null) {
// We check for data sources matching the following names:
// 1. The persistence unit id
// 2. The web module id
// 3. The web module context root
// 4. The application module id
List<String> ids = new ArrayList<String>();
ids.add(unit.getName());
for (WebModule webModule : app.getWebModules()) {
ids.add(webModule.getModuleId());
ids.add(webModule.getContextRoot());
}
ids.add(app.getModuleId());
// Search for a matching data source
for (String id : ids) {
//Try finding a jta managed data source
required.put("JtaManaged", "true");
jtaDataSourceId = findResourceId(id, "DataSource", required, null);
if (jtaDataSourceId == null) {
//No jta managed data source found. Try finding a non-jta managed
required.clear();
required.put("JtaManaged", "false");
nonJtaDataSourceId = findResourceId(id, "DataSource", required, null);
}
if (jtaDataSourceId == null && nonJtaDataSourceId == null) {
// Neither jta nor non-jta managed data sources were found. try to find one with it unset
required.clear();
required.put("JtaManaged", NONE);
jtaDataSourceId = findResourceId(id, "DataSource", required, null);
}
if (jtaDataSourceId != null || nonJtaDataSourceId != null) {
//We have found a default. Exit the loop
break;
}
}
}
//
// If neither of the references are valid yet, then let's take
// the first valid datasource.
//
// We won't fill in both jta-data-source and non-jta-data-source
// this way as the following code does a great job at determining
// if any of the existing data sources are a good match or if
// one needs to be generated.
//
if (jtaDataSourceId == null && nonJtaDataSourceId == null){
required.clear();
required.put("JtaManaged", "true");
jtaDataSourceId = firstMatching("DataSource", required, null);
if (jtaDataSourceId == null){
required.clear();
required.put("JtaManaged", "false");
nonJtaDataSourceId = firstMatching("DataSource", required, null);
}
}
//
// Does the jta-data-source reference point an existing
// Resource in the system with JtaManaged=true?
//
// If so, we can search for an existing datasource
// configured with identical properties and use it.
//
// If that doesn't work, we can copy the jta-data-source
// and auto-create the missing non-jta-data-source
// using it as a template, applying the overrides,
// and finally setting JtaManaged=false
//
if (jtaDataSourceId != null && nonJtaDataSourceId == null){
ResourceInfo jtaResourceInfo = configFactory.getResourceInfo(jtaDataSourceId);
Properties jtaProperties = jtaResourceInfo.properties;
if (jtaProperties.containsKey("JtaManaged")){
// Strategy 1: Best match search
required.clear();
required.put("JtaManaged", "false");
for (String key : asList("JdbcDriver", "JdbcUrl")) {
if (jtaProperties.containsKey(key)) required.put(key, jtaProperties.get(key));
}
nonJtaDataSourceId = firstMatching("DataSource", required, null);
// Strategy 2: Copy
if (nonJtaDataSourceId == null) {
ResourceInfo nonJtaResourceInfo = copy(jtaResourceInfo);
nonJtaResourceInfo.id = jtaResourceInfo.id + "NonJta";
Properties overrides = ConfigurationFactory.getSystemProperties(nonJtaResourceInfo.id, nonJtaResourceInfo.service);
nonJtaResourceInfo.properties.putAll(overrides);
nonJtaResourceInfo.properties.setProperty("JtaManaged", "false");
logAutoCreateResource(nonJtaResourceInfo, "DataSource", unit.getName());
logger.info("configureService.configuring", nonJtaResourceInfo.id, nonJtaResourceInfo.service, jtaResourceInfo.id);
nonJtaDataSourceId = installResource(unit.getName(), nonJtaResourceInfo);
}
}
}
//
// Does the jta-data-source reference point an existing
// Resource in the system with JtaManaged=false?
//
// If so, we can search for an existing datasource
// configured with identical properties and use it.
//
// If that doesn't work, we can copy the jta-data-source
// and auto-create the missing non-jta-data-source
// using it as a template, applying the overrides,
// and finally setting JtaManaged=false
//
final String deduceJtaFromNonJta = SystemInstance.get().getProperty(AUTOCREATE_JTA_DATASOURCE_FROM_NON_JTA_ONE_KEY);
if (nonJtaDataSourceId != null && jtaDataSourceId == null
// hibernate uses the fact that this ds is missing to get a non jta em instead of a JTA one
&& (deduceJtaFromNonJta == null || (deduceJtaFromNonJta != null && Boolean.parseBoolean(deduceJtaFromNonJta)))) {
ResourceInfo nonJtaResourceInfo = configFactory.getResourceInfo(nonJtaDataSourceId);
Properties nonJtaProperties = nonJtaResourceInfo.properties;
if (nonJtaProperties.containsKey("JtaManaged")){
// Strategy 1: Best match search
required.clear();
required.put("JtaManaged", "true");
for (String key : asList("JdbcDriver", "JdbcUrl")) {
if (nonJtaProperties.containsKey(key)) required.put(key, nonJtaProperties.get(key));
}
jtaDataSourceId = firstMatching("DataSource", required, null);
// Strategy 2: Copy
if (jtaDataSourceId == null) {
ResourceInfo jtaResourceInfo = copy(nonJtaResourceInfo);
jtaResourceInfo.id = nonJtaResourceInfo.id + "Jta";
Properties overrides = ConfigurationFactory.getSystemProperties(jtaResourceInfo.id, jtaResourceInfo.service);
jtaResourceInfo.properties.putAll(overrides);
jtaResourceInfo.properties.setProperty("JtaManaged", "true");
logAutoCreateResource(jtaResourceInfo, "DataSource", unit.getName());
logger.info("configureService.configuring", jtaResourceInfo.id, jtaResourceInfo.service, nonJtaResourceInfo.id);
jtaDataSourceId = installResource(unit.getName(), jtaResourceInfo);
}
}
}
//
// By this point if we've found anything at all, both
// jta-data-source and non-jta-data-source should be
// filled in (provided they aren't using a third party
// data source).
//
// Should both references still be null
// we can just take a shot in the dark and auto-create
// them them both using the built-in templates for jta
// and non-jta default datasources. These are supplied
// via the service-jar.xml file.
//
if (jtaDataSourceId == null && nonJtaDataSourceId == null){
required.put("JtaManaged", "true");
jtaDataSourceId = autoCreateResource("DataSource", required, unit.getName());
required.put("JtaManaged", "false");
nonJtaDataSourceId = autoCreateResource("DataSource", required, unit.getName());
}
if (jtaDataSourceId != null) setJtaDataSource(unit, jtaDataSourceId);
if (nonJtaDataSourceId != null) setNonJtaDataSource(unit, nonJtaDataSourceId);
}
}
private void setNonJtaDataSource(PersistenceUnit unit, String current) {
String previous = unit.getNonJtaDataSource();
if (!current.equals(previous)) {
logger.info("Adjusting PersistenceUnit " + unit.getName() + " <non-jta-data-source> to Resource ID '" + current + "' from '" + previous + "'");
}
unit.setNonJtaDataSource(current);
}
private void setJtaDataSource(PersistenceUnit unit, String current) {
String previous = unit.getJtaDataSource();
if (!current.equals(previous)) {
logger.info("Adjusting PersistenceUnit " + unit.getName() + " <jta-data-source> to Resource ID '" + current + "' from '" + previous + "'");
}
unit.setJtaDataSource(current);
}
private ResourceInfo copy(ResourceInfo a) {
ResourceInfo b = new ResourceInfo();
b.id = a.id;
b.service = a.service;
b.className = a.className;
b.codebase = a.codebase;
b.displayName = a.displayName;
b.description = a.description;
b.factoryMethod = a.factoryMethod;
b.constructorArgs.addAll(a.constructorArgs);
b.types.addAll(a.types);
b.properties = new SuperProperties();
b.properties.putAll(a.properties);
return b;
}
private void checkUnitDataSourceRefs(PersistenceUnit unit) throws OpenEJBException {
Properties required = new Properties();
// check that non-jta-data-source does NOT point to a JtaManaged=true datasource
required.put("JtaManaged", "true");
String invalidNonJta = findResourceId(unit.getNonJtaDataSource(), "DataSource", required, null);
if (invalidNonJta != null){
throw new OpenEJBException("PeristenceUnit "+unit.getName()+" <non-jta-data-source> points to a jta managed Resource. Update Resource \""+invalidNonJta +"\" to \"JtaManaged=false\", use a different Resource, or delete the <non-jta-data-source> element and a default will be supplied if possible.");
}
// check that jta-data-source does NOT point to a JtaManaged=false datasource
required.put("JtaManaged", "false");
String invalidJta = findResourceId(unit.getJtaDataSource(), "DataSource", required, null);
if (invalidJta != null){
throw new OpenEJBException("PeristenceUnit "+unit.getName()+" <jta-data-source> points to a non jta managed Resource. Update Resource \""+invalidJta +"\" to \"JtaManaged=true\", use a different Resource, or delete the <jta-data-source> element and a default will be supplied if possible.");
}
}
private String findResourceProviderId(String resourceId) throws OpenEJBException {
if (resourceId == null) return null;
if (hasServiceProvider(resourceId)) {
return resourceId;
}
resourceId = toShortName(resourceId);
if (hasServiceProvider(resourceId)) {
return resourceId;
}
return null;
}
private String getResourceId(String beanName, String resourceId, String type, AppResources appResources) throws OpenEJBException {
return getResourceId(beanName, resourceId, type, null, appResources);
}
private String getResourceId(String beanName, String resourceId, String type, Properties required, AppResources appResources) throws OpenEJBException {
resourceId = normalizeResourceId(resourceId);
if(resourceId == null){
return null;
}
if (appResources == null) appResources = new AppResources();
// skip references such as URL which are automatically handled by the server
if (type != null && ignoredReferenceTypes.contains(type)) {
return null;
}
// check for existing resource with specified resourceId and type and properties
String id = findResourceId(resourceId, type, required, appResources);
if (id != null) return id;
// expand search to any type -- may be asking for a reference to a sub-type
id = findResourceId(resourceId, null, required, appResources);
if (id != null) return id;
// throw an exception or log an error
String shortName = toShortName(resourceId);
String message = "No existing resource found while attempting to Auto-link unmapped resource-ref '" + resourceId + "' of type '" + type + "' for '" + beanName + "'. Looked for Resource(id=" + resourceId + ") and Resource(id=" + shortName + ")";
if (!autoCreateResources){
throw new OpenEJBException(message);
}
logger.debug(message);
// if there is a provider with the specified name. use it
if (hasServiceProvider(resourceId)) {
ResourceInfo resourceInfo = configFactory.configureService(resourceId, ResourceInfo.class);
return installResource(beanName, resourceInfo);
} else if (hasServiceProvider(shortName)) {
ResourceInfo resourceInfo = configFactory.configureService(shortName, ResourceInfo.class);
return installResource(beanName, resourceInfo);
}
// if there are any resources of the desired type, use the first one
id = firstMatching(type, required, appResources);
if (id != null) return id;
// Auto create a resource using the first provider that can supply a resource of the desired type
return autoCreateResource(type, required, beanName);
}
private String autoCreateResource(String type, Properties required, String beanName) throws OpenEJBException {
String resourceId;
resourceId = ServiceUtils.getServiceProviderId(type, required);
if (resourceId == null) {
throw new OpenEJBException("No provider available for resource-ref '" + resourceId + "' of type '" + type + "' for '" + beanName + "'.");
}
ResourceInfo resourceInfo = configFactory.configureService(resourceId, ResourceInfo.class);
logAutoCreateResource(resourceInfo, type, beanName);
return installResource(beanName, resourceInfo);
}
private void logAutoCreateResource(ResourceInfo resourceInfo, String type, String beanName) {
logger.info("Auto-creating a Resource with id '" + resourceInfo.id + "' of type '" + type + " for '" + beanName + "'.");
}
private String firstMatching(String type, Properties required, AppResources appResources) {
List<String> resourceIds = getResourceIds(appResources, type, required);
String idd = null;
if (resourceIds.size() > 0) {
idd = resourceIds.get(0);
}
return idd;
}
private String findResourceId(String resourceId, String type, Properties required, AppResources appResources) {
if (resourceId == null) return null;
resourceId = normalizeResourceId(resourceId);
// check for existing resource with specified resourceId
List<String> resourceIds = getResourceIds(appResources, type, required);
for (String id : resourceIds) {
if (id.equalsIgnoreCase(resourceId)) return id;
}
// check for existing resource with shortName
String shortName = toShortName(resourceId);
for (String id : resourceIds) {
if (id.equalsIgnoreCase(shortName)) return id;
}
if (resourceId.startsWith("osgi:")) {
return resourceId;
}
return null;
}
private List<String> getResourceIds(AppResources appResources, String type, Properties required) {
List<String> resourceIds;
resourceIds = new ArrayList<String>();
if (appResources != null) resourceIds.addAll(appResources.getResourceIds(type));
resourceIds.addAll(configFactory.getResourceIds(type, required));
return resourceIds;
}
private String toShortName(String resourceId) {
// check for an existing resource using the short name (everything ever the final '/')
String shortName = resourceId.replaceFirst(".*/", "");
return shortName;
}
private String normalizeResourceId(String resourceId) {
if (resourceId == null) return null;
// strip off "java:comp/env"
if (resourceId.startsWith("java:comp/env/")) {
resourceId = resourceId.substring("java:comp/env/".length());
}
// strip off "java:openejb/Resource"
if (resourceId.startsWith("java:openejb/Resource/")) {
resourceId = resourceId.substring("java:openejb/Resource/".length());
}
// strip off "java:openejb/Connector"
if (resourceId.startsWith("java:openejb/Connector/")) {
resourceId = resourceId.substring("java:openejb/Connector/".length());
}
return resourceId;
}
private String installResource(String beanName, ResourceInfo resourceInfo) throws OpenEJBException {
String resourceAdapterId = resourceInfo.properties.getProperty("ResourceAdapter");
if (resourceAdapterId != null) {
String newResourceId = getResourceId(beanName, resourceAdapterId, null, null);
if (resourceAdapterId != newResourceId) {
resourceInfo.properties.setProperty("ResourceAdapter", newResourceId);
}
}
String dataSourceId = resourceInfo.properties.getProperty("DataSource");
if (dataSourceId != null && dataSourceId.length() > 0) {
String newResourceId = getResourceId(beanName, dataSourceId, null, null);
if (dataSourceId != newResourceId) {
resourceInfo.properties.setProperty("DataSource", newResourceId);
}
}
configFactory.install(resourceInfo);
return resourceInfo.id;
}
private String getResourceEnvId(String beanName, String resourceId, String type, AppResources appResources) throws OpenEJBException {
if(resourceId == null){
return null;
}
if (appResources == null) appResources = new AppResources();
// skip references such as URLs which are automatically handled by the server
if (ignoredReferenceTypes.contains(type)) {
return null;
}
resourceId = normalizeResourceId(resourceId);
// check for existing resource with specified resourceId
List<String> resourceEnvIds = getResourceIds(appResources, type, null);
for (String id : resourceEnvIds) {
if (id.equalsIgnoreCase(resourceId)) return id;
}
// throw an exception or log an error
String message = "No existing resource found while attempting to Auto-link unmapped resource-env-ref '" + resourceId + "' of type '" + type + "' for '" + beanName + "'. Looked for Resource(id=" + resourceId + ")";
if (!autoCreateResources){
throw new OpenEJBException(message);
}
logger.debug(message);
// Auto create a resource using the first provider that can supply a resource of the desired type
String providerId = ServiceUtils.getServiceProviderId(type);
if (providerId == null) {
// if there are any existing resources of the desired type, use the first one
if (resourceEnvIds.size() > 0) {
return resourceEnvIds.get(0);
}
throw new OpenEJBException("No provider available for resource-env-ref '" + resourceId + "' of type '" + type + "' for '" + beanName + "'.");
}
Resource resource = new Resource(resourceId, null, providerId);
resource.getProperties().setProperty("destination", resourceId);
ResourceInfo resourceInfo = configFactory.configureService(resource, ResourceInfo.class);
logAutoCreateResource(resourceInfo, type, beanName);
return installResource(beanName, resourceInfo);
}
private String getUsableContainer(Class<? extends ContainerInfo> containerInfoType, Object bean, AppResources appResources) {
if (bean instanceof MessageDrivenBean) {
MessageDrivenBean messageDrivenBean = (MessageDrivenBean) bean;
String messagingType = messageDrivenBean.getMessagingType();
List<String> containerIds = appResources.containerIdsByType.get(messagingType);
if (containerIds != null && !containerIds.isEmpty()) {
return containerIds.get(0);
}
}
for (ContainerInfo containerInfo : configFactory.getContainerInfos()) {
if (containerInfo.getClass().equals(containerInfoType)){
// MDBs must match message listener interface type
if (bean instanceof MessageDrivenBean) {
MessageDrivenBean messageDrivenBean = (MessageDrivenBean) bean;
String messagingType = messageDrivenBean.getMessagingType();
if (containerInfo.properties.get("MessageListenerInterface").equals(messagingType)) {
return containerInfo.id;
}
} else {
return containerInfo.id;
}
}
}
return null;
}
private static class AppResources {
@SuppressWarnings({"MismatchedQueryAndUpdateOfCollection"})
private final Set<String> resourceAdapterIds = new TreeSet<String>();
private final Map<String,List<String>> resourceIdsByType = new TreeMap<String,List<String>>();
private final Map<String,List<String>> resourceEnvIdsByType = new TreeMap<String,List<String>>();
private final Map<String,List<String>> containerIdsByType = new TreeMap<String,List<String>>();
public AppResources() {
}
public AppResources(AppModule appModule) {
//
// DEVELOPERS NOTE: if you change the id generation code here, you must change
// the id generation code in ConfigurationFactory.configureApplication(AppModule appModule)
//
for (ConnectorModule connectorModule : appModule.getConnectorModules()) {
Connector connector = connectorModule.getConnector();
ResourceAdapter resourceAdapter = connector.getResourceAdapter();
if (resourceAdapter.getResourceAdapterClass() != null) {
String resourceAdapterId;
if (resourceAdapter.getId() != null) {
resourceAdapterId = resourceAdapter.getId();
} else {
resourceAdapterId = connectorModule.getModuleId() + "RA";
}
resourceAdapterIds.add(resourceAdapterId);
}
OutboundResourceAdapter outbound = resourceAdapter.getOutboundResourceAdapter();
if (outbound != null) {
for (ConnectionDefinition connection : outbound.getConnectionDefinition()) {
String type = connection.getConnectionFactoryInterface();
String resourceId;
if (connection.getId() != null) {
resourceId = connection.getId();
} else if (outbound.getConnectionDefinition().size() == 1) {
resourceId = connectorModule.getModuleId();
} else {
resourceId = connectorModule.getModuleId() + "-" + type;
}
List<String> resourceIds = resourceIdsByType.get(type);
if (resourceIds == null) {
resourceIds = new ArrayList<String>();
resourceIdsByType.put(type, resourceIds);
}
resourceIds.add(resourceId);
}
}
InboundResourceadapter inbound = resourceAdapter.getInboundResourceAdapter();
if (inbound != null) {
for (MessageListener messageListener : inbound.getMessageAdapter().getMessageListener()) {
String type = messageListener.getMessageListenerType();
String containerId;
if (messageListener.getId() != null) {
containerId = messageListener.getId();
} else if (inbound.getMessageAdapter().getMessageListener().size() == 1) {
containerId = connectorModule.getModuleId();
} else {
containerId = connectorModule.getModuleId() + "-" + type;
}
List<String> containerIds = containerIdsByType.get(type);
if (containerIds == null) {
containerIds = new ArrayList<String>();
containerIdsByType.put(type, containerIds);
}
containerIds.add(containerId);
}
}
for (AdminObject adminObject : resourceAdapter.getAdminObject()) {
String type = adminObject.getAdminObjectInterface();
String resourceEnvId;
if (adminObject.getId() != null) {
resourceEnvId = adminObject.getId();
} else if (resourceAdapter.getAdminObject().size() == 1) {
resourceEnvId = connectorModule.getModuleId();
} else {
resourceEnvId = connectorModule.getModuleId() + "-" + type;
}
List<String> resourceEnvIds = resourceEnvIdsByType.get(type);
if (resourceEnvIds == null) {
resourceEnvIds = new ArrayList<String>();
resourceEnvIdsByType.put(type, resourceEnvIds);
}
resourceEnvIds.add(resourceEnvId);
}
}
// for (EjbModule module : appModule.getEjbModules()) {
// EnterpriseBean[] enterpriseBeans = module.getEjbJar().getEnterpriseBeans();
// OpenejbJar openejbJar = module.getOpenejbJar();
// Map<String, EjbDeployment> deployments = openejbJar.getDeploymentsByEjbName();
//
// for (DatasourceDefinition ds : module.getDatasources()) {
// final String id = module.getUniqueId() + '/' + ds.getName().replace("java:", "");
// if (resourceIdsByType.get("javax.sql.DataSource") == null) {
// resourceIdsByType.put("javax.sql.DataSource", new ArrayList<String>());
// }
// resourceIdsByType.get("javax.sql.DataSource").add(id);
//
// for (EnterpriseBean bean : enterpriseBeans) {
// EjbDeployment ejbDeployment = deployments.get(bean.getEjbName());
// for (ResourceRef ref : bean.getResourceRef()) {
// if (ds.getName().equals(ref.getName())) {
// ResourceLink link = new ResourceLink();
// link.setResId(id);
// link.setResRefName(ds.getName());
// ejbDeployment.addResourceLink(link);
// }
// }
// }
// }
// }
}
public List<String> getResourceIds(String type) {
if (type == null) {
List<String> allResourceIds = new ArrayList<String>();
for (List<String> resourceIds : resourceIdsByType.values()) {
allResourceIds.addAll(resourceIds);
}
return allResourceIds;
}
List<String> resourceIds = resourceIdsByType.get(type);
if (resourceIds != null) {
return resourceIds;
}
return Collections.emptyList();
}
public List<String> getResourceEnvIds(String type) {
if (type != null) {
List<String> resourceIds = resourceEnvIdsByType.get(type);
if (resourceIds != null) {
return resourceIds;
}
}
return Collections.emptyList();
}
public List<String> getContainerIds() {
ArrayList<String> ids = new ArrayList<String>();
for (List<String> list : containerIdsByType.values()) {
ids.addAll(list);
}
return ids;
}
}
}