com.sun.enterprise.connectors.module.ConnectorDeployer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2018-2021] [Payara Foundation and/or its affiliates]
package com.sun.enterprise.connectors.module;
import com.sun.appserv.connectors.internal.api.ConnectorClassFinder;
import com.sun.appserv.connectors.internal.api.ConnectorConstants;
import com.sun.appserv.connectors.internal.api.ConnectorRuntimeException;
import com.sun.appserv.connectors.internal.api.ConnectorsUtil;
import com.sun.enterprise.config.serverbeans.*;
import com.sun.enterprise.config.serverbeans.Module;
import com.sun.enterprise.connectors.ConnectorRegistry;
import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.enterprise.connectors.util.ResourcesUtil;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.ConnectorDescriptor;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.logging.LogDomains;
import org.glassfish.api.ActionReport;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.api.deployment.MetaData;
import org.glassfish.api.deployment.OpsParams;
import org.glassfish.api.deployment.UndeployCommandParameters;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.Events;
import org.glassfish.connectors.config.*;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.PreDestroy;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.api.DelegatingClassLoader;
import org.glassfish.internal.api.Target;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.javaee.core.deployment.JavaEEDeployer;
import org.glassfish.resources.listener.ApplicationScopedResourcesManager;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.SingleConfigCode;
import org.jvnet.hk2.config.TransactionFailure;
import jakarta.inject.Inject;
import jakarta.validation.*;
import jakarta.validation.bootstrap.GenericBootstrap;
import java.beans.PropertyVetoException;
import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Deployer for a resource-adapter.
*
* @author Jagadish Ramu
*/
@Service
public class ConnectorDeployer extends JavaEEDeployer
implements PostConstruct, PreDestroy, EventListener {
@Inject
private ConnectorRuntime runtime;
@Inject
private ClassLoaderHierarchy clh;
@Inject
private org.glassfish.resourcebase.resources.listener.ResourceManager resourceManager;
@Inject
private ApplicationScopedResourcesManager asrManager;
@Inject
private Domain domain;
@Inject
private ServerEnvironment env;
private Resources resources;
@Inject
private Events events;
@Inject
private ConfigBeansUtilities configBeansUtilities;
private static Logger _logger = LogDomains.getLogger(ConnectorDeployer.class, LogDomains.RSR_LOGGER);
private static StringManager localStrings = StringManager.getManager(ConnectorRuntime.class);
private static final String DOMAIN = "domain";
private static final String EAR = "ear";
public ConnectorDeployer() {
}
/**
* Returns the meta data assocated with this Deployer
*
* @return the meta data for this Deployer
*/
public MetaData getMetaData() {
return new MetaData(false, null,
new Class[]{Application.class});
}
/**
* Loads the meta date associated with the application.
*
* @param type type of metadata that this deployer has declared providing.
*/
public T loadMetaData(Class type, DeploymentContext context) {
return null;
}
/**
* Loads a previously prepared application in its execution environment and
* return a ContractProvider instance that will identify this environment in
* future communications with the application's container runtime.
*
* @param container in which the application will reside
* @param context of the deployment
* @return an ApplicationContainer instance identifying the running application
*/
@Override
public ConnectorApplication load(ConnectorContainer container, DeploymentContext context) {
super.load(container, context);
File sourceDir = context.getSourceDir();
String sourcePath = sourceDir.getAbsolutePath();
String moduleName = sourceDir.getName();
ConnectorDescriptor connDesc =
context.getModuleMetaData(ConnectorDescriptor.class);
if (connDesc != null) {
connDesc.setClassLoader(context.getClassLoader());
}
if(_logger.isLoggable(Level.FINEST)){
_logger.finest("connector-descriptor during load : " + connDesc);
}
boolean isEmbedded = ConnectorsUtil.isEmbedded(context);
ConnectorClassFinder ccf = null;
ClassLoader classLoader = null;
//this check is not needed as system-rars are never deployed, just to be safe.
if (!ConnectorsUtil.belongsToSystemRA(moduleName)) {
try {
//for a connector deployer, classloader will always be ConnectorClassFinder
classLoader = context.getClassLoader();
//for embedded .rar, compute the embedded .rar name
if (isEmbedded) {
moduleName = ConnectorsUtil.getEmbeddedRarModuleName(
ConnectorsUtil.getApplicationName(context), moduleName);
}
//don't add the class-finder to the chain if its embedded .rar
if (!(isEmbedded)) {
ccf = (ConnectorClassFinder) context.getClassLoader();
clh.getConnectorClassLoader(null).addDelegate(ccf);
}
registerBeanValidator(moduleName, context.getSource(), classLoader);
runtime.createActiveResourceAdapter(connDesc, moduleName, sourcePath, classLoader);
} catch (Exception cre) {
Object params[] = new Object[]{moduleName, cre};
_logger.log(Level.WARNING, "unable.to.load.ra", params);
//since resource-adapter creation has failed, remove the class-loader for the RAR
if (!(isEmbedded) && ccf != null) {
clh.getConnectorClassLoader(null).removeDelegate(ccf);
}
//since resource-adapter creation has failed, unregister bean validator of the RAR
unregisterBeanValidator(moduleName);
throw new RuntimeException(cre.getMessage(), cre);
}
}
return new ConnectorApplication(moduleName, ConnectorsUtil.getApplicationName(context), resourceManager,
asrManager, classLoader, runtime, events, connDesc);
}
/**
* Unload or stop a previously running application identified with the
* ContractProvider instance. The container will be stop upon return from this
* method.
*
* @param appContainer instance to be stopped
* @param context of the undeployment
*/
public void unload(ConnectorApplication appContainer, DeploymentContext context) {
String moduleName = appContainer.getModuleName();
try {
runtime.destroyActiveResourceAdapter(moduleName);
} catch (ConnectorRuntimeException e) {
Object params[] = new Object[]{moduleName, e};
_logger.log(Level.WARNING, "unable.to.unload.ra", params);
} finally {
//remove it only if it is not embedded
if (!ConnectorsUtil.isEmbedded(context)) {
//remove the class-finder (class-loader) from connector-class-loader chain
DelegatingClassLoader dcl = clh.getConnectorClassLoader(null);
for(DelegatingClassLoader.ClassFinder cf : dcl.getDelegates()){
ConnectorClassFinder ccf = (ConnectorClassFinder)cf;
if(ccf.getResourceAdapterName().equals(moduleName)){
dcl.removeDelegate(ccf);
break;
}
}
}
unregisterBeanValidator(moduleName);
}
}
/**
* Clean any files and artifacts that were created during the execution
* of the prepare method.
*
* @param dc deployment context
*/
public void clean(DeploymentContext dc) {
super.clean(dc);
//delete resource configuration
UndeployCommandParameters dcp = dc.getCommandParameters(UndeployCommandParameters.class);
if (dcp != null && dcp.origin == OpsParams.Origin.undeploy) {
if (dcp.cascade != null && dcp.cascade) {
File sourceDir = dc.getSourceDir();
String moduleName = sourceDir.getName();
if (ConnectorsUtil.isEmbedded(dc)) {
String applicationName = ConnectorsUtil.getApplicationName(dc);
moduleName = ConnectorsUtil.getEmbeddedRarModuleName(applicationName, moduleName);
}
deleteAllResources(moduleName, dcp.target);
}
}
}
/**
* deletes all resources (pool, resource, admin-object-resource, ra-config, work-security-map) of a resource-adapter)
*
* @param moduleName resource-adapter name
* @param targetServer target instance name
*/
private void deleteAllResources(String moduleName, String targetServer) {
Collection conPools = ConnectorsUtil.getAllPoolsOfModule(moduleName, resources);
Collection poolNames = ConnectorsUtil.getAllPoolNames(conPools);
Collection connectorResources = ConnectorsUtil.getAllResources(poolNames, resources);
Collection adminObjectResources = ResourcesUtil.createInstance().
getEnabledAdminObjectResources(moduleName);
Collection securityMaps = ConnectorsUtil.getAllWorkSecurityMaps(resources, moduleName);
ResourceAdapterConfig rac = ConnectorsUtil.getRAConfig(moduleName, resources);
deleteConnectorResources(connectorResources, targetServer, moduleName);
deleteConnectionPools(conPools, moduleName);
deleteAdminObjectResources(adminObjectResources, targetServer, moduleName);
deleteWorkSecurityMaps(securityMaps, moduleName);
deleteRAConfig(rac);
}
private void deleteRAConfig(final ResourceAdapterConfig rac) {
if (rac != null) {
try {
// delete resource-adapter-config
if (ConfigSupport.apply(new SingleConfigCode() {
public Object run(Resources param) throws PropertyVetoException, TransactionFailure {
return param.getResources().remove(rac);
}
}, resources) == null) {
_logger.log(Level.WARNING, "unable.to.delete.rac", rac.getResourceAdapterName());
}
} catch (TransactionFailure tfe) {
Object params[] = new Object[]{rac.getResourceAdapterName(), tfe};
_logger.log(Level.WARNING, "unable.to.delete.rac.exception", params);
}
}
}
private void deleteWorkSecurityMaps(final Collection workSecurityMaps, String raName) {
if (workSecurityMaps.size() > 0) {
try {
// delete work-security-maps
if (ConfigSupport.apply(new SingleConfigCode() {
public Object run(Resources param) throws PropertyVetoException,
TransactionFailure {
for (WorkSecurityMap resource : workSecurityMaps) {
param.getResources().remove(resource);
}
return true; // indicating that removal was successful
}
}, resources) == null) {
_logger.log(Level.WARNING, "unable.to.delete.work.security.map", raName);
}
} catch (TransactionFailure tfe) {
Object params[] = new Object[]{raName, tfe};
_logger.log(Level.WARNING, "unable.to.delete.work.security.map.exception", params);
}
}
}
private void deleteAdminObjectResources(final Collection adminObjectResources,
final String target, String raName) {
if (adminObjectResources != null && adminObjectResources.size() > 0) {
try {
//delete resource-refs
for (AdminObjectResource resource : adminObjectResources) {
String jndiName = resource.getJndiName();
deleteResourceRef(jndiName, target);
}
// delete admin-object-resource
if (ConfigSupport.apply(new SingleConfigCode() {
public Object run(Resources param) throws PropertyVetoException, TransactionFailure {
for (AdminObjectResource resource : adminObjectResources) {
param.getResources().remove(resource);
}
// not found
return true;
}
}, resources) == null) {
_logger.log(Level.WARNING, "unable.to.delete.admin.object", raName);
}
} catch (TransactionFailure tfe) {
Object params[] = new Object[]{raName, tfe};
_logger.log(Level.WARNING, "unable.to.delete.admin.object.exception", params);
}
}
}
private void deleteConnectorResources(final Collection connectorResources, final String target,
String raName) {
if (connectorResources.size() > 0) {
try {
//delete resource-refs
for (Resource resource : connectorResources) {
String jndiName = ((ConnectorResource) resource).getJndiName();
deleteResourceRef(jndiName, target);
}
// delete connector-resource
if (ConfigSupport.apply(new SingleConfigCode() {
public Object run(Resources param) throws PropertyVetoException, TransactionFailure {
for (Resource resource : connectorResources) {
param.getResources().remove(resource);
}
// not found
return true;
}
}, resources) == null) {
_logger.log(Level.WARNING, "unable.to.delete.connector.resource", raName);
}
} catch (TransactionFailure tfe) {
Object params[] = new Object[]{raName, tfe};
_logger.log(Level.WARNING, "unable.to.delete.connector.resource.exception", params);
}
}
}
private void deleteResourceRef(String jndiName, String target) throws TransactionFailure {
if (target.equals(DOMAIN)) {
return ;
}
if( domain.getConfigNamed(target) != null){
return ;
}
Server server = configBeansUtilities.getServerNamed(target);
if (server != null) {
if (server.isResourceRefExists(jndiName)) {
// delete ResourceRef for Server
server.deleteResourceRef(jndiName);
}
} else {
Cluster cluster = domain.getClusterNamed(target);
if(cluster != null){
if (cluster.isResourceRefExists(jndiName)) {
// delete ResourceRef of Cluster
cluster.deleteResourceRef(jndiName);
// delete ResourceRef for all instances of Cluster
Target tgt = habitat.getService(Target.class);
List instances = tgt.getInstances(target);
for (Server svr : instances) {
if (svr.isResourceRefExists(jndiName)) {
svr.deleteResourceRef(jndiName);
}
}
}
}
}
}
private void deleteConnectionPools(final Collection conPools, String raName) {
if (conPools.size() > 0) {
// delete connector connection pool
try {
if (ConfigSupport.apply(new SingleConfigCode() {
public Object run(Resources param) throws PropertyVetoException, TransactionFailure {
for (ConnectorConnectionPool cp : conPools) {
return param.getResources().remove(cp);
}
// not found
return null;
}
}, resources) == null) {
_logger.log(Level.WARNING, "unable.to.delete.connector.connection.pool", raName);
}
} catch (TransactionFailure tfe) {
Object params[] = new Object[]{raName, tfe};
_logger.log(Level.WARNING, "unable.to.delete.connector.connection.pool.exception", params);
}
}
}
/**
* The component has been injected with any dependency and
* will be placed into commission by the subsystem.
*/
public void postConstruct() {
resources = domain.getResources();
events.register(this);
}
public void logFine(String message) {
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, message);
}
}
private void registerBeanValidator(String rarName, ReadableArchive archive, ClassLoader classLoader) {
ClassLoader contextCL = null;
try {
contextCL = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
Validator beanValidator = null;
ValidatorFactory validatorFactory = null;
try {
List mappingsList = getValidationMappingDescriptors(archive);
if (mappingsList.size() > 0) {
GenericBootstrap bootstrap = Validation.byDefaultProvider();
Configuration config = bootstrap.configure();
InputStream inputStream = null;
try {
for (String fileName : mappingsList) {
inputStream = archive.getEntry(fileName);
config.addMapping(inputStream);
}
validatorFactory = config.buildValidatorFactory();
ValidatorContext validatorContext = validatorFactory.usingContext();
beanValidator = validatorContext.getValidator();
} catch (IOException e) {
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Exception while processing xml files for detecting " +
"bean-validation-mapping", e);
}
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
// ignore ?
}
}
}
} catch (Exception e) {
Object params[] = new Object[]{rarName, e};
_logger.log(Level.WARNING, "error.processing.xml.for.bean.validation.mapping", params);
}
if (beanValidator == null) {
validatorFactory = Validation.byDefaultProvider().configure().buildValidatorFactory();
beanValidator = validatorFactory.getValidator();
}
ConnectorRegistry registry = ConnectorRegistry.getInstance();
registry.addBeanValidator(rarName, beanValidator);
} finally {
Thread.currentThread().setContextClassLoader(contextCL);
}
}
private List getValidationMappingDescriptors(ReadableArchive archive) {
String validationMappingNSName = "jboss.org/xml/ns/jakarta/validation/mapping";
Enumeration entries = archive.entries();
List mappingList = new ArrayList();
while (entries.hasMoreElements()) {
String fileName = (String) entries.nextElement();
if (fileName.toUpperCase(Locale.getDefault()).endsWith(".XML")) {
BufferedReader reader = null;
try {
InputStream is = archive.getEntry(fileName);
reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(validationMappingNSName)) {
mappingList.add(fileName);
break;
}
}
} catch (IOException e) {
if(_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Exception while processing xml file [ " + fileName + " ] " +
"for detecting bean-validation-mapping", e);
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
//ignore ?
}
}
}
}
}
return mappingList;
}
private void unregisterBeanValidator(String rarName){
ConnectorRegistry registry = ConnectorRegistry.getInstance();
registry.removeBeanValidator(rarName);
}
public void event(Event event) {
// added this pre-check so as to validate whether connector-resources referring
// the application (that has rar or is an standalone rar) are present.
// Though similar validation is done in 'ConnectorApplication', this is to
// handle the case where the application is not enabled in DAS (no ConnectorApplication)
if (/*env.isDas() && */ Deployment.UNDEPLOYMENT_VALIDATION.equals(event.type())) {
//this is an application undeploy event
DeploymentContext dc = (DeploymentContext) event.hook();
UndeployCommandParameters dcp = dc.getCommandParameters(UndeployCommandParameters.class);
String appName = dcp.name;
Boolean cascade = dcp.cascade;
Boolean ignoreCascade = dcp._ignoreCascade;
if (cascade != null && ignoreCascade != null) {
if (cascade || ignoreCascade) {
return;
}
}
com.sun.enterprise.config.serverbeans.Application app = domain.getApplications().getApplication(appName);
boolean isRAR = false;
if (app != null && Boolean.valueOf(app.getEnabled())) {
isRAR = app.containsSnifferType(ConnectorConstants.CONNECTOR_MODULE);
}
if (!isRAR) {
return;
}
boolean isAppRefEnabled = false;
Server server = domain.getServers().getServer(env.getInstanceName());
ApplicationRef appRef = server.getApplicationRef(appName);
if (appRef != null && Boolean.valueOf(appRef.getEnabled())) {
isAppRefEnabled = true;
}
if (isAppRefEnabled) {
return;
}
boolean isEAR = app.containsSnifferType(EAR);
String moduleName = appName;
ResourcesUtil resourcesUtil = ResourcesUtil.createInstance();
if (isEAR) {
List modules = app.getModule();
for (Module module : modules) {
moduleName = module.getName();
if (module.getEngine(ConnectorConstants.CONNECTOR_MODULE) != null) {
moduleName = appName + ConnectorConstants.EMBEDDEDRAR_NAME_DELIMITER + moduleName;
if (moduleName.toLowerCase(Locale.getDefault()).endsWith(".rar")) {
int index = moduleName.lastIndexOf(".rar");
moduleName = moduleName.substring(0, index);
if (resourcesUtil.filterConnectorResources
(resourceManager.getAllResources(), moduleName, true).size() > 0) {
setFailureStatus(dc, moduleName);
return;
}
}
}
}
} else {
if (resourcesUtil.filterConnectorResources
(resourceManager.getAllResources(), moduleName, true).size() > 0) {
setFailureStatus(dc, moduleName);
}
}
}
}
private void setFailureStatus(DeploymentContext dc, String moduleName) {
String message = localStrings.getString("con.deployer.resources.exist", moduleName);
_logger.log(Level.WARNING, "resources.of.rar.exist", moduleName);
ActionReport report = dc.getActionReport();
report.setActionExitCode(ActionReport.ExitCode.FAILURE);
report.setMessage(message);
}
public void preDestroy() {
events.unregister(this);
}
}