/*
* IronJacamar, a Java EE Connector Architecture implementation
* Copyright 2015, Red Hat Inc, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the Eclipse Public License 1.0 as
* published by the Free Software Foundation.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse
* Public License for more details.
*
* You should have received a copy of the Eclipse Public License
* along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.ironjacamar.deployers.common;
import org.ironjacamar.common.api.metadata.Defaults;
import org.ironjacamar.common.api.metadata.common.Extension;
import org.ironjacamar.common.api.metadata.common.TransactionSupportEnum;
import org.ironjacamar.common.api.metadata.resourceadapter.Activation;
import org.ironjacamar.common.api.metadata.resourceadapter.AdminObject;
import org.ironjacamar.common.api.metadata.resourceadapter.ConnectionDefinition;
import org.ironjacamar.common.api.metadata.spec.Connector;
import org.ironjacamar.common.api.metadata.spec.InboundResourceAdapter;
import org.ironjacamar.common.api.metadata.spec.XsdString;
import org.ironjacamar.core.api.connectionmanager.ConnectionManagerConfiguration;
import org.ironjacamar.core.api.connectionmanager.ccm.CachedConnectionManager;
import org.ironjacamar.core.api.connectionmanager.pool.PoolConfiguration;
import org.ironjacamar.core.api.deploymentrepository.Deployment;
import org.ironjacamar.core.api.deploymentrepository.DeploymentRepository;
import org.ironjacamar.core.api.metadatarepository.Metadata;
import org.ironjacamar.core.api.metadatarepository.MetadataRepository;
import org.ironjacamar.core.bootstrapcontext.BootstrapContextCoordinator;
import org.ironjacamar.core.bootstrapcontext.CloneableBootstrapContext;
import org.ironjacamar.core.connectionmanager.ConnectionManager;
import org.ironjacamar.core.connectionmanager.ConnectionManagerFactory;
import org.ironjacamar.core.connectionmanager.pool.Capacity;
import org.ironjacamar.core.connectionmanager.pool.JanitorFactory;
import org.ironjacamar.core.connectionmanager.pool.PoolFactory;
import org.ironjacamar.core.connectionmanager.pool.capacity.CapacityFactory;
import org.ironjacamar.core.deploymentrepository.ActivationSpecImpl;
import org.ironjacamar.core.deploymentrepository.AdminObjectImpl;
import org.ironjacamar.core.deploymentrepository.ConfigPropertyImpl;
import org.ironjacamar.core.deploymentrepository.ConnectionFactoryImpl;
import org.ironjacamar.core.deploymentrepository.DeploymentBuilder;
import org.ironjacamar.core.deploymentrepository.PoolImpl;
import org.ironjacamar.core.deploymentrepository.RecoveryImpl;
import org.ironjacamar.core.deploymentrepository.ResourceAdapterImpl;
import org.ironjacamar.core.metadatarepository.MetadataImpl;
import org.ironjacamar.core.recovery.DefaultRecoveryPlugin;
import org.ironjacamar.core.spi.bv.BeanValidation;
import org.ironjacamar.core.spi.classloading.ClassLoaderPlugin;
import org.ironjacamar.core.spi.naming.JndiStrategy;
import org.ironjacamar.core.spi.recovery.RecoveryPlugin;
import org.ironjacamar.core.spi.security.SubjectFactory;
import org.ironjacamar.core.spi.transaction.TransactionIntegration;
import org.ironjacamar.core.spi.transaction.recovery.XAResourceRecovery;
import org.ironjacamar.core.util.Injection;
import org.ironjacamar.deployers.DeployersBundle;
import org.ironjacamar.deployers.DeployersLogger;
import org.ironjacamar.validator.Failure;
import org.ironjacamar.validator.FailureHelper;
import org.ironjacamar.validator.Key;
import org.ironjacamar.validator.Severity;
import org.ironjacamar.validator.Validate;
import org.ironjacamar.validator.ValidateClass;
import org.ironjacamar.validator.Validator;
import org.ironjacamar.validator.ValidatorException;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.resource.spi.ResourceAdapterAssociation;
import javax.resource.spi.TransactionSupport;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidatorFactory;
import org.jboss.logging.Messages;
/**
* Base class for resource adapter deployers
* @author <a href="mailto:jesper.pedersen@ironjacamar.org">Jesper Pedersen</a>
*/
public abstract class AbstractResourceAdapterDeployer
{
/** The bundle */
private static DeployersBundle bundle = Messages.getBundle(DeployersBundle.class);
/** the logger **/
protected final DeployersLogger log;
/** The DeploymentRepository */
protected DeploymentRepository deploymentRepository;
/** The MetadataRepository */
protected MetadataRepository metadataRepository;
/** The BootstrapContext */
protected BootstrapContextCoordinator bootstrapContextCoordinator;
/** The JndiStrategy */
protected JndiStrategy jndiStrategy;
/** The TransactionIntegration */
protected TransactionIntegration transactionIntegration;
/** The CachedConnectionManager */
protected CachedConnectionManager cachedConnectionManager;
/** The Subject Factory */
protected SubjectFactory subjectFactory;
/** The class loader plugin */
protected ClassLoaderPlugin classLoaderPlugin;
/** The bean validation */
protected BeanValidation beanValidation;
/** The default pool type */
protected String defaultPoolType;
/** archiveValidation option */
protected boolean archiveValidation;
/** archiveValidation FailOnWarn option */
protected boolean archiveValidationFailOnWarn;
/** archiveValidation FailOnError option */
protected boolean archiveValidationFailOnError;
/** List of objs needing a validation */
private List<Validate> validationObj = new ArrayList<>();
/**
* Constructor
*/
public AbstractResourceAdapterDeployer()
{
this.log = getLogger();
this.deploymentRepository = null;
this.metadataRepository = null;
this.bootstrapContextCoordinator = null;
this.jndiStrategy = null;
this.transactionIntegration = null;
this.cachedConnectionManager = null;
this.subjectFactory = null;
this.classLoaderPlugin = null;
this.beanValidation = null;
this.defaultPoolType = null;
this.archiveValidation = false;
this.archiveValidationFailOnError = false;
this.archiveValidationFailOnWarn = false;
}
/**
* Set the deployment repository
* @param v The value
*/
public void setDeploymentRepository(DeploymentRepository v)
{
this.deploymentRepository = v;
}
/**
* Set the metadata repository
* @param v The value
*/
public void setMetadataRepository(MetadataRepository v)
{
this.metadataRepository = v;
}
/**
* Set the bootstrap context
* @param v The value
*/
public void setBootstrapContextCoordinator(BootstrapContextCoordinator v)
{
this.bootstrapContextCoordinator = v;
}
/**
* Set the JNDI strategy
* @param v The value
*/
public void setJndiStrategy(JndiStrategy v)
{
this.jndiStrategy = v;
}
/**
* Set the transaction integration
* @param v The value
*/
public void setTransactionIntegration(TransactionIntegration v)
{
this.transactionIntegration = v;
}
/**
* Set the subject factory
* @param subjectFactory The value
*/
public void setSubjectFactory(SubjectFactory subjectFactory)
{
this.subjectFactory = subjectFactory;
}
/**
* Set the class loader plugin
* @param classLoaderPlugin The value
*/
public void setClassLoaderPlugin(ClassLoaderPlugin classLoaderPlugin)
{
this.classLoaderPlugin = classLoaderPlugin;
}
/**
* Set the cached connection manager
* @param v The value
*/
public void setCachedConnectionManager(CachedConnectionManager v)
{
this.cachedConnectionManager = v;
}
/**
* Set the bean validation
* @param v The value
*/
public void setBeanValidation(BeanValidation v)
{
this.beanValidation = v;
}
/**
* Set the default pool type
* @param v The value
*/
public void setDefaultPoolType(String v)
{
this.defaultPoolType = v;
}
/**
* Set the archive validation option
* @param archiveValidation the boolean setting the config option
*/
public void setArchiveValidation(boolean archiveValidation)
{
this.archiveValidation = archiveValidation;
}
/**
* Set the fail on warn option
* @param archiveValidationFailOnWarn the boolean setting the config option
*/
public void setArchiveValidationFailOnWarn(boolean archiveValidationFailOnWarn)
{
this.archiveValidationFailOnWarn = archiveValidationFailOnWarn;
}
/**
* Set the fail on error option
* @param archiveValidationFailOnError the boolean setting the config option
*/
public void setArchiveValidationFailOnError(boolean archiveValidationFailOnError)
{
this.archiveValidationFailOnError = archiveValidationFailOnError;
}
/**
* Register a metadata instance with the repository
* @param name The name
* @param c The connector metadata
* @param archive The archive
* @return The metadata instance registered
*/
public Metadata registerMetadata(String name, Connector c, File archive)
{
Metadata md = new MetadataImpl(name, c, archive);
metadataRepository.registerMetadata(md);
return md;
}
/**
* Activate a resource adapter
* @param connector The merged metadata
* @param activation The activation
* @param archiveName The name of the archive
* @param root The root directory of the extracted resource adapter
* @param cl The class loader
* @return The deployment
* @exception DeployException Thrown if a deployment error occurs
*/
public Deployment activate(Connector connector, Activation activation, String archiveName, File root, ClassLoader cl)
throws DeployException
{
log.tracef("Connector=%s", connector);
log.tracef("Activation=%s", stripPassword(activation.toString()));
log.tracef("ArchiveName=%s", archiveName);
log.tracef("Root=%s", root.getAbsolutePath());
try
{
DeploymentBuilder builder = new DeploymentBuilder();
TransactionSupportEnum transactionSupport = getTransactionSupport(connector, activation);
Metadata md = metadataRepository.findByName(archiveName);
builder.identifier(activation.getId());
builder.name(md.getName());
builder.metadata(connector);
builder.activation(activation);
builder.archive(md.getArchive());
builder.classLoader(cl);
builder.classLoaderPlugin(classLoaderPlugin);
loadNativeLibraries(root);
if (connector.getResourceadapter().getResourceadapterClass() != null)
{
CloneableBootstrapContext bootstrapContext = createBootstrapContext(connector, activation);
createResourceAdapter(builder, connector.getResourceadapter().getResourceadapterClass(),
connector.getResourceadapter().getConfigProperties(), activation.getConfigProperties(),
transactionSupport, getProductName(connector), getProductVersion(connector),
connector.getResourceadapter().getInboundResourceadapter(), bootstrapContext);
}
if (activation.getConnectionDefinitions() != null)
{
for (ConnectionDefinition cd : activation.getConnectionDefinitions())
{
createConnectionDefinition(builder, connector, cd, transactionSupport);
}
}
if (activation.getAdminObjects() != null)
{
for (AdminObject ao : activation.getAdminObjects())
{
createAdminObject(builder, connector, ao);
}
}
Deployment deployment = builder.build();
Set<Failure> failures = new HashSet<>();
failures = validateArchive(validationObj, failures);
if (archiveValidationFailOnWarn &&
(hasFailuresLevel(failures, Severity.WARNING) || hasFailuresLevel(failures, Severity.ERROR)) ||
(archiveValidationFailOnError && hasFailuresLevel(failures, Severity.ERROR)))
{
Validator v = new Validator();
throw new ValidatorException(printFailuresLog(v, failures), failures,
v.getResourceBundle());
}
else
{
if (failures != null && failures.size() > 0)
{
log.validationInvalidArchive(root.getName());
}
printFailuresLog(new Validator(), failures);
}
if (is16(deployment.getMetadata()))
verifyBeanValidation(deployment);
deployment.activate();
if (!deploymentRepository.registerDeployment(deployment))
throw new DeployException(bundle.unableToRegister(deployment.getIdentifier(), deployment.getName()));
log.deployed(archiveName);
return deployment;
}
catch (DeployException de)
{
throw de;
}
catch (Exception e)
{
throw new DeployException(bundle.deploymentFailed(archiveName), e);
}
}
private CloneableBootstrapContext createBootstrapContext(Connector connector, Activation activation)
{
CloneableBootstrapContext bootstrapContext;
String bootstrapContextName;
if (activation != null && activation.getBootstrapContext() != null &&
!activation.getBootstrapContext().trim().equals(""))
{
bootstrapContextName = activation.getBootstrapContext();
String bootstrapContextIdentifier = bootstrapContextCoordinator
.createIdentifier(connector.getResourceadapter().getResourceadapterClass(),
connector.getResourceadapter().getConfigProperties(), bootstrapContextName);
bootstrapContext = bootstrapContextCoordinator
.createBootstrapContext(bootstrapContextIdentifier, bootstrapContextName);
}
else
{
bootstrapContext = bootstrapContextCoordinator.getDefaultBootstrapContext();
}
return bootstrapContext;
}
/**
* Create resource adapter instance
* @param builder The deployment builder
* @param raClz The resource adapter class
* @param configProperties The config properties
* @param overrides The config properties overrides
* @param transactionSupport The transaction support level
* @param productName The product name
* @param productVersion The product version
* @param ira The inbound resource adapter definition
* @param bootstrapContext the bootstrapContext to use
* @throws DeployException Thrown if the resource adapter cant be created
*/
protected void
createResourceAdapter(DeploymentBuilder builder,
String raClz,
Collection<org.ironjacamar.common.api.metadata.spec.ConfigProperty> configProperties,
Map<String, String> overrides,
TransactionSupportEnum transactionSupport,
String productName, String productVersion,
InboundResourceAdapter ira, CloneableBootstrapContext bootstrapContext)
throws DeployException
{
try
{
Class<?> clz = Class.forName(raClz, true, builder.getClassLoader());
javax.resource.spi.ResourceAdapter resourceAdapter =
(javax.resource.spi.ResourceAdapter)clz.newInstance();
validationObj.add(new ValidateClass(Key.RESOURCE_ADAPTER, clz, configProperties));
Collection<org.ironjacamar.core.api.deploymentrepository.ConfigProperty> dcps =
injectConfigProperties(resourceAdapter, configProperties, overrides, builder.getClassLoader());
org.ironjacamar.core.spi.statistics.StatisticsPlugin statisticsPlugin = null;
if (resourceAdapter instanceof org.ironjacamar.core.spi.statistics.Statistics)
statisticsPlugin = ((org.ironjacamar.core.spi.statistics.Statistics)resourceAdapter).getStatistics();
TransactionIntegration ti = null;
if (isXA(transactionSupport))
{
ti = transactionIntegration;
}
bootstrapContext.setResourceAdapter(resourceAdapter);
builder.resourceAdapter(new ResourceAdapterImpl(resourceAdapter, bootstrapContext, dcps,
statisticsPlugin, productName, productVersion,
createInboundMapping(ira, builder.getClassLoader()),
is16(builder.getMetadata()), beanValidation,
builder.getActivation().getBeanValidationGroups(),
ti));
}
catch (Throwable t)
{
throw new DeployException(bundle.unableToCreateResourceAdapter(raClz), t);
}
}
/**
* Create connection definition instance
* @param builder The deployment builder
* @param connector The metadata
* @param cd The connection definition
* @param transactionSupport The transaction support level
* @throws DeployException Thrown if the connection definition cant be created
*/
protected void
createConnectionDefinition(DeploymentBuilder builder,
Connector connector,
ConnectionDefinition cd,
TransactionSupportEnum transactionSupport)
throws DeployException
{
try
{
TransactionSupportEnum tse = transactionSupport;
String mcfClass = findManagedConnectionFactory(cd.getClassName(), connector);
Class<?> clz = Class.forName(mcfClass, true, builder.getClassLoader());
javax.resource.spi.ManagedConnectionFactory mcf =
(javax.resource.spi.ManagedConnectionFactory)clz.newInstance();
Collection<org.ironjacamar.common.api.metadata.spec.ConfigProperty> configProperties =
findConfigProperties(mcfClass, connector);
validationObj.add(new ValidateClass(Key.MANAGED_CONNECTION_FACTORY, clz, configProperties));
Collection<org.ironjacamar.core.api.deploymentrepository.ConfigProperty> dcps =
injectConfigProperties(mcf, configProperties, cd.getConfigProperties(),
builder.getClassLoader());
if (mcf instanceof TransactionSupport)
{
TransactionSupport.TransactionSupportLevel tsl = ((TransactionSupport) mcf).getTransactionSupport();
if (tsl == TransactionSupport.TransactionSupportLevel.NoTransaction)
{
tse = TransactionSupportEnum.NoTransaction;
}
else if (tsl == TransactionSupport.TransactionSupportLevel.LocalTransaction)
{
tse = TransactionSupportEnum.LocalTransaction;
}
else
{
tse = TransactionSupportEnum.XATransaction;
}
if (tse != transactionSupport)
log.changedTransactionSupport(cd.getJndiName());
}
ConnectionManagerConfiguration cmc = new ConnectionManagerConfiguration();
applyConnectionManagerConfiguration(cmc, cd);
applyConnectionManagerConfiguration(cmc, cd.getSecurity());
applyConnectionManagerConfiguration(cmc, cd.getTimeout());
if (isXA(tse))
applyConnectionManagerConfiguration(cmc, (org.ironjacamar.common.api.metadata.common.XaPool)cd.getPool());
ConnectionManager cm =
ConnectionManagerFactory.createConnectionManager(tse, mcf,
cd.isUseCcm() ? cachedConnectionManager : null,
cmc,
transactionIntegration);
if (subjectFactory != null)
cm.setSubjectFactory(subjectFactory);
String poolType = cd.getPool() != null ? cd.getPool().getType() : null;
String janitorType = cd.getPool() != null ? cd.getPool().getJanitor() : null;
if (poolType == null || poolType.equals(""))
poolType = defaultPoolType;
PoolConfiguration pc = new PoolConfiguration();
pc.setId(cd.getId() != null ? cd.getId() : cd.getJndiName());
applyPoolConfiguration(pc, cd.getPool());
applyPoolConfiguration(pc, cd.getTimeout());
applyPoolConfiguration(pc, cd.getValidation());
org.ironjacamar.core.connectionmanager.pool.Pool pool = PoolFactory.createPool(poolType, cm, pc);
cm.setPool(pool);
Capacity capacity = CapacityFactory
.create(cd.getPool() != null ? cd.getPool().getCapacity() : null, this.classLoaderPlugin);
pool.setCapacity(capacity);
org.ironjacamar.core.api.deploymentrepository.Pool dpool = new PoolImpl(pool, null,
capacity.getIncrementer(), capacity.getDecrementer());
org.ironjacamar.core.connectionmanager.pool.Janitor janitor = JanitorFactory.createJanitor(janitorType);
janitor.setPool(pool);
pool.setJanitor(janitor);
org.ironjacamar.core.spi.statistics.StatisticsPlugin statisticsPlugin = null;
if (mcf instanceof org.ironjacamar.core.spi.statistics.Statistics)
statisticsPlugin = ((org.ironjacamar.core.spi.statistics.Statistics)mcf).getStatistics();
org.ironjacamar.core.api.deploymentrepository.Recovery recovery = null;
if (isXA(tse))
{
recovery = createRecovery(mcf, cd);
}
if (builder.getResourceAdapter() != null)
associateResourceAdapter(builder.getResourceAdapter().getResourceAdapter(), mcf);
// Create ConnectionFactory
Object cf = mcf.createConnectionFactory(cm);
validationObj.add(new ValidateClass(Key.CONNECTION_FACTORY, cf.getClass()));
builder.connectionFactory(new ConnectionFactoryImpl(cd.getJndiName(), cf, dcps, cd, cm, dpool,
statisticsPlugin, recovery, jndiStrategy));
}
catch (Throwable t)
{
throw new DeployException(bundle.unableToCreateConnectionDefinition(cd.getId(), cd.getJndiName()), t);
}
}
/**
* Create admin object instance
* @param builder The deployment builder
* @param connector The metadata
* @param ao The admin object
* @throws DeployException Thrown if the admin object cant be created
*/
protected void createAdminObject(DeploymentBuilder builder, Connector connector, AdminObject ao)
throws DeployException
{
try
{
String aoClass = findAdminObject(ao.getClassName(), connector);
Class<?> clz = Class.forName(aoClass, true, builder.getClassLoader());
Object adminObject = clz.newInstance();
Collection<org.ironjacamar.common.api.metadata.spec.ConfigProperty> configProperties = findConfigProperties(
aoClass, connector);
Collection<org.ironjacamar.core.api.deploymentrepository.ConfigProperty> dcps = injectConfigProperties(
adminObject, configProperties, ao.getConfigProperties(), builder.getClassLoader());
validationObj.add(new ValidateClass(Key.ADMIN_OBJECT, clz, configProperties));
org.ironjacamar.core.spi.statistics.StatisticsPlugin statisticsPlugin = null;
if (adminObject instanceof org.ironjacamar.core.spi.statistics.Statistics)
statisticsPlugin = ((org.ironjacamar.core.spi.statistics.Statistics)adminObject).getStatistics();
if (builder.getResourceAdapter() != null)
associateResourceAdapter(builder.getResourceAdapter().getResourceAdapter(), adminObject);
builder.adminObject(new AdminObjectImpl(ao.getJndiName(), adminObject, dcps, ao,
statisticsPlugin, jndiStrategy));
}
catch (Throwable t)
{
throw new DeployException(bundle.unableToCreateAdminObject(ao.getId(), ao.getJndiName()), t);
}
}
/**
* Find the ManagedConnectionFactory class
* @param className The initial class name
* @param connector The metadata
* @return The ManagedConnectionFactory
*/
private String findManagedConnectionFactory(String className, Connector connector)
{
for (org.ironjacamar.common.api.metadata.spec.ConnectionDefinition cd :
connector.getResourceadapter().getOutboundResourceadapter().getConnectionDefinitions())
{
if (className.equals(cd.getManagedConnectionFactoryClass().getValue()) ||
className.equals(cd.getConnectionFactoryInterface().getValue()))
return cd.getManagedConnectionFactoryClass().getValue();
}
return className;
}
/**
* Find the AdminObject class
* @param className The initial class name
* @param connector The metadata
* @return The AdminObject
*/
private String findAdminObject(String className, Connector connector)
{
for (org.ironjacamar.common.api.metadata.spec.AdminObject ao :
connector.getResourceadapter().getAdminObjects())
{
if (className.equals(ao.getAdminobjectClass().getValue()) ||
className.equals(ao.getAdminobjectInterface().getValue()))
return ao.getAdminobjectClass().getValue();
}
return className;
}
/**
* Find the config properties for the class
* @param className The class name
* @param connector The metadata
* @return The config properties
*/
private Collection<org.ironjacamar.common.api.metadata.spec.ConfigProperty>
findConfigProperties(String className, Connector connector)
{
for (org.ironjacamar.common.api.metadata.spec.ConnectionDefinition cd :
connector.getResourceadapter().getOutboundResourceadapter().getConnectionDefinitions())
{
if (className.equals(cd.getManagedConnectionFactoryClass().getValue()) ||
className.equals(cd.getConnectionFactoryInterface().getValue()))
return cd.getConfigProperties();
}
return null;
}
/**
* Inject the config properties into the object
* @param o The object
* @param configProperties The config properties
* @param overrides The overrides
* @param classLoader The class loader
* @return The deployment data
* @exception Throwable Thrown if an error occurs
*/
private Collection<org.ironjacamar.core.api.deploymentrepository.ConfigProperty>
injectConfigProperties(Object o,
Collection<org.ironjacamar.common.api.metadata.spec.ConfigProperty> configProperties,
Map<String, String> overrides,
ClassLoader classLoader)
throws Throwable
{
Collection<org.ironjacamar.core.api.deploymentrepository.ConfigProperty> dcps = null;
if (configProperties != null && !configProperties.isEmpty())
{
Injection injector = new Injection();
dcps = new ArrayList<org.ironjacamar.core.api.deploymentrepository.ConfigProperty>(configProperties.size());
for (org.ironjacamar.common.api.metadata.spec.ConfigProperty cp : configProperties)
{
String name = cp.getConfigPropertyName().getValue();
Class<?> type = Class.forName(cp.getConfigPropertyType().getValue(), true, classLoader);
boolean readOnly = cp.getConfigPropertySupportsDynamicUpdates() != null ?
cp.getConfigPropertySupportsDynamicUpdates().booleanValue() : true;
boolean confidential = cp.getConfigPropertyConfidential() != null ?
cp.getConfigPropertyConfidential().booleanValue() : false;
boolean declared = true;
Object value = cp.isValueSet() ? cp.getConfigPropertyValue().getValue() : null;
if (overrides != null)
{
if (overrides.containsKey(cp.getConfigPropertyName().getValue()))
{
value = overrides.get(cp.getConfigPropertyName().getValue());
}
else
{
String alternative = cp.getConfigPropertyName().getValue().substring(0, 1).toUpperCase();
if (cp.getConfigPropertyName().getValue().length() > 1)
alternative += cp.getConfigPropertyName().getValue().substring(1);
if (overrides.containsKey(alternative))
{
value = overrides.get(alternative);
}
else
{
log.tracef("%s: Override for %s not found", o.getClass().getName(),
cp.getConfigPropertyName().getValue());
}
}
}
if (value != null)
{
try
{
injector.inject(o,
cp.getConfigPropertyName().getValue(),
value,
cp.getConfigPropertyType().getValue());
}
catch (Throwable t)
{
type = convertType(type);
if (type != null)
{
injector.inject(o,
cp.getConfigPropertyName().getValue(),
value,
type.getName());
}
else
{
throw new DeployException(bundle.unableToInject(o.getClass().getName(),
cp.getConfigPropertyName().getValue(),
value.toString()), t);
}
}
}
dcps.add(new ConfigPropertyImpl(o, name, type,
value, readOnly, confidential,
declared));
}
}
return dcps;
}
/**
* Convert type if possible
* @param old The old type
* @return The new type; otherwise <code>null</code>
*/
private Class<?> convertType(Class<?> old)
{
if (Boolean.class.equals(old))
{
return boolean.class;
}
else if (boolean.class.equals(old))
{
return Boolean.class;
}
else if (Byte.class.equals(old))
{
return byte.class;
}
else if (byte.class.equals(old))
{
return Byte.class;
}
else if (Short.class.equals(old))
{
return short.class;
}
else if (short.class.equals(old))
{
return Short.class;
}
else if (Integer.class.equals(old))
{
return int.class;
}
else if (int.class.equals(old))
{
return Integer.class;
}
else if (Long.class.equals(old))
{
return long.class;
}
else if (long.class.equals(old))
{
return Long.class;
}
else if (Float.class.equals(old))
{
return float.class;
}
else if (float.class.equals(old))
{
return Float.class;
}
else if (Double.class.equals(old))
{
return double.class;
}
else if (double.class.equals(old))
{
return Double.class;
}
else if (Character.class.equals(old))
{
return char.class;
}
else if (char.class.equals(old))
{
return Character.class;
}
return null;
}
/**
* Is a support type
* @param t The type
* @return True if supported, otherwise false
*/
private boolean isSupported(Class<?> t)
{
if (Boolean.class.equals(t) || boolean.class.equals(t) ||
Byte.class.equals(t) || byte.class.equals(t) ||
Short.class.equals(t) || short.class.equals(t) ||
Integer.class.equals(t) || int.class.equals(t) ||
Long.class.equals(t) || long.class.equals(t) ||
Float.class.equals(t) || float.class.equals(t) ||
Double.class.equals(t) || double.class.equals(t) ||
Character.class.equals(t) || char.class.equals(t) ||
String.class.equals(t))
return true;
return false;
}
/**
* Associate resource adapter with the object if it implements ResourceAdapterAssociation
* @param resourceAdapter The resource adapter
* @param object The possible association object
* @throws DeployException Thrown if the resource adapter cant be associated
*/
@SuppressWarnings("unchecked")
protected void associateResourceAdapter(javax.resource.spi.ResourceAdapter resourceAdapter, Object object)
throws DeployException
{
if (resourceAdapter != null && object != null && object instanceof ResourceAdapterAssociation)
{
try
{
ResourceAdapterAssociation raa = (ResourceAdapterAssociation)object;
raa.setResourceAdapter(resourceAdapter);
}
catch (Throwable t)
{
throw new DeployException(bundle.unableToAssociate(object.getClass().getName()), t);
}
}
}
/**
* Get the transaction support level
* @param connector The spec metadata
* @param activation The activation
* @return True if XA, otherwise false
*/
private TransactionSupportEnum getTransactionSupport(Connector connector, Activation activation)
{
if (activation.getTransactionSupport() != null)
return activation.getTransactionSupport();
if (connector.getResourceadapter().getOutboundResourceadapter() != null)
return connector.getResourceadapter().getOutboundResourceadapter().getTransactionSupport();
// We have to assume XA for pure inbound, overrides is done with activation
return TransactionSupportEnum.XATransaction;
}
/**
* Is XA deployment
* @param tse The transaction support level
* @return True if XA, otherwise false
*/
private boolean isXA(TransactionSupportEnum tse)
{
return TransactionSupportEnum.XATransaction == tse;
}
/**
* Apply connection definition to connection manager configuration
* @param cmc The connection manager configuration
* @param cd The connection definition definition
*/
private void applyConnectionManagerConfiguration(ConnectionManagerConfiguration cmc,
org.ironjacamar.common.api.metadata.resourceadapter.ConnectionDefinition cd)
{
if (cd.getJndiName() != null)
cmc.setJndiName(cd.getJndiName());
if (cd.isSharable() != null)
cmc.setSharable(cd.isSharable());
if (cd.isEnlistment() != null)
cmc.setEnlistment(cd.isEnlistment());
if (cd.isConnectable() != null)
cmc.setConnectable(cd.isConnectable());
if (cd.isTracking() != null)
cmc.setTracking(cd.isTracking());
}
/**
* Apply security to connection manager configuration
* @param cmc The connection manager configuration
* @param s The security definition
*/
private void applyConnectionManagerConfiguration(ConnectionManagerConfiguration cmc,
org.ironjacamar.common.api.metadata.common.Security s)
{
if (s != null && s.getSecurityDomain() != null)
{
cmc.setSecurityDomain(s.getSecurityDomain());
}
}
/**
* Apply xa-pool to connection manager configuration
* @param cmc The connection manager configuration
* @param xp The xa-pool definition
*/
private void applyConnectionManagerConfiguration(ConnectionManagerConfiguration cmc,
org.ironjacamar.common.api.metadata.common.XaPool xp)
{
if (xp != null)
{
if (xp.isIsSameRmOverride() != null)
cmc.setIsSameRMOverride(xp.isIsSameRmOverride());
if (xp.isPadXid() != null)
cmc.setPadXid(xp.isPadXid());
if (xp.isWrapXaResource() != null)
cmc.setWrapXAResource(xp.isWrapXaResource());
}
}
/**
* Apply timeout to connection manager configuration
* @param cmc The connection manager configuration
* @param t The timeout definition
*/
private void applyConnectionManagerConfiguration(ConnectionManagerConfiguration cmc,
org.ironjacamar.common.api.metadata.common.Timeout t)
{
if (t != null)
{
if (t.getAllocationRetry() != null)
cmc.setAllocationRetry(t.getAllocationRetry());
if (t.getAllocationRetryWaitMillis() != null)
cmc.setAllocationRetryWaitMillis(t.getAllocationRetryWaitMillis());
if (t.getXaResourceTimeout() != null)
cmc.setXAResourceTimeout(t.getXaResourceTimeout());
}
}
/**
* Apply pool to pool configuration
* @param pc The pool configuration
* @param p The pool definition
*/
private void applyPoolConfiguration(PoolConfiguration pc,
org.ironjacamar.common.api.metadata.common.Pool p)
{
if (p != null)
{
if (p.getMinPoolSize() != null)
pc.setMinSize(p.getMinPoolSize().intValue());
if (p.getInitialPoolSize() != null)
pc.setInitialSize(p.getInitialPoolSize().intValue());
if (p.getMaxPoolSize() != null)
pc.setMaxSize(p.getMaxPoolSize().intValue());
if (p.isPrefill() != null)
pc.setPrefill(p.isPrefill().booleanValue());
if (p.getFlushStrategy() != null)
pc.setFlushStrategy(p.getFlushStrategy());
}
}
/**
* Apply timeout to pool configuration
* @param pc The pool configuration
* @param t The timeout definition
*/
private void applyPoolConfiguration(PoolConfiguration pc,
org.ironjacamar.common.api.metadata.common.Timeout t)
{
if (t != null)
{
if (t.getBlockingTimeoutMillis() != null)
pc.setBlockingTimeout(t.getBlockingTimeoutMillis().longValue());
if (t.getIdleTimeoutMinutes() != null)
pc.setIdleTimeoutMinutes(t.getIdleTimeoutMinutes().intValue());
}
}
/**
* Apply validation to pool configuration
* @param pc The pool configuration
* @param v The validation definition
*/
private void applyPoolConfiguration(PoolConfiguration pc,
org.ironjacamar.common.api.metadata.common.Validation v)
{
if (v != null)
{
if (v.isValidateOnMatch() != null)
pc.setValidateOnMatch(v.isValidateOnMatch().booleanValue());
if (v.isBackgroundValidation() != null)
pc.setBackgroundValidation(v.isBackgroundValidation().booleanValue());
if (v.getBackgroundValidationMillis() != null)
pc.setBackgroundValidationMillis(v.getBackgroundValidationMillis().longValue());
if (v.isUseFastFail() != null)
pc.setUseFastFail(v.isUseFastFail().booleanValue());
}
}
/**
* Create a recovery module
* @param mcf The ManagedConnectionFactory
* @param cd The connection definition
* @return The recovery module, or <code>null</code> if no recovery
* @exception Throwable In case on an error
*/
private org.ironjacamar.core.api.deploymentrepository.Recovery
createRecovery(javax.resource.spi.ManagedConnectionFactory mcf, ConnectionDefinition cd) throws Throwable
{
Boolean padXid = Defaults.PAD_XID;
Boolean isSameRMOverride = Defaults.IS_SAME_RM_OVERRIDE;
Boolean wrapXAResource = Defaults.WRAP_XA_RESOURCE;
String securityDomain = null;
RecoveryPlugin plugin = null;
Collection<org.ironjacamar.core.api.deploymentrepository.ConfigProperty> dcps = null;
if (transactionIntegration.getRecoveryRegistry() == null)
return null;
if (subjectFactory == null)
return null;
if (cd.getRecovery() != null && cd.getRecovery().isNoRecovery())
return null;
// Check security domain
if (cd.getRecovery() != null && cd.getRecovery().getCredential() != null)
securityDomain = cd.getRecovery().getCredential().getSecurityDomain();
if (securityDomain == null && cd.getSecurity() != null)
securityDomain = cd.getSecurity().getSecurityDomain();
if (securityDomain == null)
return null;
if (cd.getRecovery() != null && cd.getRecovery().getPlugin() != null)
{
Extension extension = cd.getRecovery().getPlugin();
Collection<org.ironjacamar.common.api.metadata.spec.ConfigProperty> configProperties =
new ArrayList<org.ironjacamar.common.api.metadata.spec.ConfigProperty>();
for (Map.Entry<String, String> property : extension.getConfigPropertiesMap().entrySet())
{
org.ironjacamar.common.api.metadata.spec.ConfigProperty c =
new org.ironjacamar.common.metadata.spec.ConfigPropertyImpl(null,
new XsdString(property.getKey(), null),
XsdString.NULL_XSDSTRING,
new XsdString(property.getValue(), null),
Boolean.FALSE, Boolean.FALSE,
Boolean.FALSE,
null, false,
null, null, null, null);
configProperties.add(c);
}
Class<?> clz = Class.forName(extension.getClassName(), true, mcf.getClass().getClassLoader());
plugin = (RecoveryPlugin)clz.newInstance();
dcps = injectConfigProperties(plugin, configProperties, null, plugin.getClass().getClassLoader());
}
if (plugin == null)
plugin = new DefaultRecoveryPlugin();
if (dcps == null)
dcps = new ArrayList<>(1);
if (cd.getPool() != null)
{
org.ironjacamar.common.api.metadata.common.XaPool xaPool =
(org.ironjacamar.common.api.metadata.common.XaPool)cd.getPool();
if (xaPool.isPadXid() != null)
padXid = xaPool.isPadXid();
if (xaPool.isIsSameRmOverride() != null)
isSameRMOverride = xaPool.isIsSameRmOverride();
if (xaPool.isWrapXaResource() != null)
wrapXAResource = xaPool.isWrapXaResource();
}
XAResourceRecovery r = transactionIntegration.createXAResourceRecovery(mcf,
padXid,
isSameRMOverride,
wrapXAResource,
securityDomain,
subjectFactory,
plugin,
null);
return new RecoveryImpl(plugin.getClass().getName(), dcps, r, cd.getJndiName(),
transactionIntegration.getRecoveryRegistry());
}
/**
* Create an inbound mapping
* @param ira The inbound resource adapter definition
* @param cl The class loader
* @return The mapping
* @exception Exception Thrown in case of an error
*/
private Map<String, ActivationSpecImpl> createInboundMapping(InboundResourceAdapter ira, ClassLoader cl)
throws Exception
{
if (ira != null)
{
Map<String, ActivationSpecImpl> result = new HashMap<>();
for (org.ironjacamar.common.api.metadata.spec.MessageListener ml :
ira.getMessageadapter().getMessagelisteners())
{
String type = ml.getMessagelistenerType().getValue();
org.ironjacamar.common.api.metadata.spec.Activationspec as = ml.getActivationspec();
String clzName = as.getActivationspecClass().getValue();
Class<?> clz = Class.forName(clzName, true, cl);
Map<String, Class<?>> configProperties = createPropertyMap(clz);
Set<String> requiredConfigProperties = new HashSet<>();
if (as.getRequiredConfigProperties() != null)
{
for (org.ironjacamar.common.api.metadata.spec.RequiredConfigProperty rcp :
as.getRequiredConfigProperties())
{
requiredConfigProperties.add(rcp.getConfigPropertyName().getValue());
}
}
validationObj.add(new ValidateClass(Key.ACTIVATION_SPEC, clz, as.getConfigProperties()));
ActivationSpecImpl asi = new ActivationSpecImpl(clzName, configProperties, requiredConfigProperties);
if (!result.containsKey(type))
result.put(type, asi);
}
return result;
}
return null;
}
/**
* Get property map
* @param clz The class
* @return The map
* @exception Exception Thrown in case of an error
*/
private Map<String, Class<?>> createPropertyMap(Class<?> clz) throws Exception
{
Map<String, Class<?>> result = new HashMap<>();
for (Method m : clz.getMethods())
{
if (m.getName().startsWith("set"))
{
if (m.getReturnType().equals(Void.TYPE) &&
m.getParameterCount() == 1 &&
isSupported(m.getParameterTypes()[0]))
result.put(m.getName().substring(3), m.getParameterTypes()[0]);
}
}
return result;
}
/**
* Get the product name for the resource adapter
* @param raXml The connector
* @return The value
*/
private String getProductName(Connector raXml)
{
if (raXml != null && !XsdString.isNull(raXml.getEisType()))
return raXml.getEisType().getValue();
return "";
}
/**
* Get the product version for the resource adapter
* @param raXml The connector
* @return The value
*/
private String getProductVersion(Connector raXml)
{
if (raXml != null && !XsdString.isNull(raXml.getResourceadapterVersion()))
return raXml.getResourceadapterVersion().getValue();
return "";
}
/**
* Strip password
* @param str The string
* @return The result
*/
private String stripPassword(String str)
{
if (str.indexOf("<password>") == -1)
return str;
Pattern pattern = Pattern.compile("<password>[^<]*</password>");
String[] strs = pattern.split(str);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strs.length; i++)
{
String s = strs[i];
sb.append(s);
if (i < strs.length - 1)
sb.append("<password>****</password>");
}
return sb.toString();
}
/**
* Is a 1.6+ deployment
* @param connector The metadata
* @return True if 1.6+, otherwise false
*/
private boolean is16(Connector connector)
{
if (connector == null ||
connector.getVersion() == Connector.Version.V_16 ||
connector.getVersion() == Connector.Version.V_17)
return true;
return false;
}
/**
* Verify deployment against bean validation
* @param deployment The deployment
* @exception DeployException Thrown in case of a violation
*/
@SuppressWarnings("unchecked")
private void verifyBeanValidation(Deployment deployment) throws DeployException
{
if (beanValidation != null)
{
ValidatorFactory vf = null;
try
{
vf = beanValidation.getValidatorFactory();
javax.validation.Validator v = vf.getValidator();
Collection<String> l = deployment.getActivation().getBeanValidationGroups();
if (l == null || l.isEmpty())
l = Arrays.asList(javax.validation.groups.Default.class.getName());
Collection<Class<?>> groups = new ArrayList<>();
for (String clz : l)
{
try
{
groups.add(Class.forName(clz, true, deployment.getClassLoader()));
}
catch (ClassNotFoundException e)
{
throw new DeployException(bundle.unableToLoadBeanValidationGroup(clz, deployment.getIdentifier()),
e);
}
}
Set failures = new HashSet();
if (deployment.getResourceAdapter() != null)
{
Set f = v.validate(deployment.getResourceAdapter().getResourceAdapter(),
groups.toArray(new Class<?>[groups.size()]));
if (!f.isEmpty())
failures.addAll(f);
}
if (deployment.getConnectionFactories() != null)
{
for (org.ironjacamar.core.api.deploymentrepository.ConnectionFactory cf :
deployment.getConnectionFactories())
{
Set f = v.validate(cf.getConnectionFactory(), groups.toArray(new Class<?>[groups.size()]));
if (!f.isEmpty())
failures.addAll(f);
}
}
if (deployment.getAdminObjects() != null)
{
for (org.ironjacamar.core.api.deploymentrepository.AdminObject ao :
deployment.getAdminObjects())
{
Set f = v.validate(ao.getAdminObject(), groups.toArray(new Class<?>[groups.size()]));
if (!f.isEmpty())
failures.addAll(f);
}
}
if (!failures.isEmpty())
{
throw new DeployException(bundle.violationOfValidationRule(deployment.getIdentifier()),
new ConstraintViolationException(failures));
}
}
finally
{
if (vf != null)
vf.close();
}
}
}
/**
* Load native libraries
* @param root The deployment root
*/
private void loadNativeLibraries(File root)
{
if (root != null && root.exists())
{
List<String> libs = new ArrayList<String>();
if (root.isDirectory())
{
if (root.listFiles() != null)
{
for (File f : root.listFiles())
{
if (f.isFile())
{
String fileName = f.getName().toLowerCase(Locale.US);
if (fileName.endsWith(".a") || fileName.endsWith(".so") || fileName.endsWith(".dll"))
{
libs.add(f.getAbsolutePath());
}
}
}
}
else
{
log.debugf("Root is a directory, but there were an I/O error: %s", root.getAbsolutePath());
}
}
if (libs.size() > 0)
{
for (String lib : libs)
{
try
{
SecurityActions.load(lib);
log.debugf("Loaded library: %s", lib);
}
catch (Throwable t)
{
log.debugf("Unable to load library: %s", lib);
}
}
}
else
{
log.debugf("No native libraries for %s", root.getAbsolutePath());
}
}
}
/**
* validate archive
*
* @param archiveValidationObjs archiveValidation archiveValidation classes and/or to validate.
* @param failures failures failures original list of failures
* @return The list of failures gotten with all new failures added. Null in case of no failures
* or if validation is not run according to archiveValidation Setting. It returns null also if
* the concrete implementation of this class set validateClasses instance variable to flase and the list of
* archiveValidation contains one or more instance of {@link ValidateClass} type
*/
public Set<Failure> validateArchive(List<Validate> archiveValidationObjs, Set<Failure> failures)
{
// Archive validation
if (!archiveValidation)
{
return null;
}
for (Validate validate : archiveValidationObjs)
{
if (!(validate instanceof Validate))
return null;
}
org.ironjacamar.validator.Validator validator = new org.ironjacamar.validator.Validator();
List<Failure> partialFailures = validator.validate(archiveValidationObjs);
if (partialFailures != null)
{
if (failures == null)
{
failures = new HashSet<>();
}
failures.addAll(partialFailures);
}
return failures;
}
/**
* Check for failures at a certain level
* @param failures failures failures The failures
* @param severity severity severity The level
* @return True if a failure is found with the specified severity; otherwise false
*/
protected boolean hasFailuresLevel(Collection<Failure> failures, int severity)
{
if (failures != null)
{
for (Failure failure : failures)
{
if (failure.getSeverity() == severity)
{
return true;
}
}
}
return false;
}
/**
* print Failures into Log files.
*
* @param validator validator validator validator instance used to run validation rules
* @param failures failures failures the list of Failures to be printed
* @param fhInput fhInput fhInput optional parameter. Normally used only for test or in case of
* FailureHelper already present in context
* @return the error Text
*
*/
public String printFailuresLog(Validator validator, Collection<Failure> failures, FailureHelper... fhInput)
{
String errorText = "";
FailureHelper fh = null;
if (fhInput.length == 0)
fh = new FailureHelper(failures);
else
fh = fhInput[0];
if (failures != null && failures.size() > 0)
{
errorText = fh.asText(validator.getResourceBundle());
}
return errorText;
}
/**
* Get the logger
* @return The value
*/
protected abstract DeployersLogger getLogger();
/**
*
* get The directory where write error reports
*
* @return the directory as {@link File}
*/
protected File getReportDirectory()
{
return new File(SecurityActions.getSystemProperty("ironjacamar.home"), "/log/");
}
}