/* * 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/"); } }