| /* |
| * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| package com.sun.enterprise.connectors.inbound; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.Vector; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| import jakarta.inject.Inject; |
| import jakarta.inject.Provider; |
| import jakarta.resource.spi.ActivationSpec; |
| import javax.transaction.xa.XAResource; |
| |
| import com.sun.appserv.connectors.internal.api.ConnectorConstants; |
| import com.sun.appserv.connectors.internal.api.ConnectorRuntime; |
| import com.sun.appserv.connectors.internal.api.ConnectorRuntimeException; |
| import com.sun.appserv.connectors.internal.api.ConnectorsUtil; |
| import com.sun.enterprise.config.serverbeans.Application; |
| import com.sun.enterprise.config.serverbeans.Applications; |
| import com.sun.enterprise.config.serverbeans.ConfigBeansUtilities; |
| import com.sun.enterprise.connectors.ConnectorRegistry; |
| import com.sun.enterprise.connectors.service.ConnectorAdminServiceUtils; |
| import com.sun.enterprise.connectors.util.RARUtils; |
| import com.sun.enterprise.connectors.util.ResourcesUtil; |
| import com.sun.enterprise.connectors.util.SetMethodAction; |
| import com.sun.enterprise.deployment.BundleDescriptor; |
| import com.sun.enterprise.deployment.EjbBundleDescriptor; |
| import com.sun.enterprise.deployment.EjbDescriptor; |
| import com.sun.enterprise.deployment.EjbMessageBeanDescriptor; |
| import com.sun.enterprise.transaction.spi.RecoveryResourceHandler; |
| import com.sun.logging.LogDomains; |
| import org.glassfish.internal.data.ApplicationInfo; |
| import org.glassfish.internal.data.ApplicationRegistry; |
| import org.jvnet.hk2.annotations.Service; |
| |
| |
| /** |
| * Recovery handler for Inbound transactions |
| * |
| * @author Jagadish Ramu |
| */ |
| @Service |
| public class InboundRecoveryHandler implements RecoveryResourceHandler { |
| |
| @Inject |
| private Applications deployedApplications; |
| |
| @Inject |
| private ApplicationRegistry appsRegistry; |
| |
| @Inject |
| private Provider<ConnectorRuntime> connectorRuntimeProvider; |
| |
| @Inject |
| private ConfigBeansUtilities configBeansUtilities; |
| |
| |
| private static Logger _logger = LogDomains.getLogger(InboundRecoveryHandler.class, LogDomains.RSR_LOGGER); |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void loadXAResourcesAndItsConnections(List xaresList, List connList) { |
| Vector<XAResource> xaResources = new Vector<XAResource>(); |
| recoverInboundTransactions(xaResources); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void closeConnections(List connList) { |
| // do nothing |
| } |
| |
| private void recoverInboundTransactions(List<XAResource> xaresList) { |
| |
| List<Application> applications = deployedApplications.getApplications(); |
| |
| try { |
| _logger.log(Level.INFO, "Recovery of Inbound Transactions started."); |
| |
| if (applications.size() == 0) { |
| _logger.log(Level.FINE, "No applications deployed."); |
| return; |
| } |
| // List of CMT enabled MDB descriptors on the application server instance. |
| List<EjbDescriptor> xaEnabledMDBList = new ArrayList<EjbDescriptor>(); |
| |
| //Done so as to initialize connectors-runtime before loading inbound active RA. need a better way ? |
| ConnectorRuntime cr = connectorRuntimeProvider.get(); |
| |
| for (Application application : applications) { |
| Vector ejbDescVec = getEjbDescriptors(application, appsRegistry); |
| for (int j = 0; j < ejbDescVec.size(); j++) { |
| EjbDescriptor desc = (EjbDescriptor) ejbDescVec.elementAt(j); |
| // If EjbDescriptor is an instance of a CMT enabled MDB descriptor, |
| // add it to the list of xaEnabledMDBList. |
| if (desc instanceof EjbMessageBeanDescriptor && |
| desc.getTransactionType(). |
| equals(EjbDescriptor.CONTAINER_TRANSACTION_TYPE)) { |
| xaEnabledMDBList.add(desc); |
| _logger.log(Level.FINE, "Found a CMT MDB: " |
| + desc.getEjbClassName()); |
| } |
| } |
| } |
| |
| if (xaEnabledMDBList.size() == 0) { |
| _logger.log(Level.FINE, "Found no CMT MDBs in all applications"); |
| return; |
| } |
| |
| ConnectorRegistry creg = ConnectorRegistry.getInstance(); |
| |
| // for each RA (key in the map) get the list (value) of MDB Descriptors |
| Map<String, List<EjbDescriptor>> mappings = createRAEjbMapping(xaEnabledMDBList); |
| |
| //For each RA |
| for (Map.Entry entry : mappings.entrySet()) { |
| |
| String raMid = (String) entry.getKey(); |
| List<EjbDescriptor> respectiveDesc = mappings.get(raMid); |
| |
| try { |
| createActiveResourceAdapter(raMid); |
| } catch (Exception ex) { |
| _logger.log(Level.SEVERE, "error.loading.connector.resources.during.recovery", raMid); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, ex.toString(), ex); |
| } |
| } |
| |
| ActiveInboundResourceAdapter activeInboundRA = (ActiveInboundResourceAdapter) creg |
| .getActiveResourceAdapter(raMid); |
| |
| //assert activeInboundRA instanceof ActiveInboundResourceAdapter; |
| |
| boolean isSystemJmsRA = false; |
| if (ConnectorsUtil.isJMSRA(activeInboundRA.getModuleName())) { |
| isSystemJmsRA = true; |
| } |
| |
| jakarta.resource.spi.ResourceAdapter resourceAdapter = activeInboundRA |
| .getResourceAdapter(); |
| // activationSpecList represents the ActivationSpec[] that would be |
| // sent to the getXAResources() method. |
| ArrayList<ActivationSpec> activationSpecList = new ArrayList<ActivationSpec>(); |
| |
| try { |
| for (int i = 0; i < respectiveDesc.size(); i++) { |
| try { |
| // Get a MessageBeanDescriptor from respectiveDesc ArrayList |
| EjbMessageBeanDescriptor descriptor = |
| (EjbMessageBeanDescriptor) respectiveDesc.get(i); |
| // A descriptor using 1.3 System JMS RA style properties needs |
| // to be updated J2EE 1.4 style props. |
| if (isSystemJmsRA) { |
| //XXX: Find out the pool descriptor corres to MDB and update |
| //MDBRuntimeInfo with that. |
| activeInboundRA.updateMDBRuntimeInfo(descriptor, null); |
| } |
| |
| // Get the ActivationConfig Properties from the MDB Descriptor |
| Set activationConfigProps = |
| RARUtils.getMergedActivationConfigProperties(descriptor); |
| // get message listener type |
| String msgListenerType = descriptor.getMessageListenerType(); |
| |
| // start resource adapter and get ActivationSpec class for |
| // the given message listener type from the ConnectorRuntime |
| |
| ActivationSpec aspec = (ActivationSpec) (Class.forName( |
| cr.getActivationSpecClass(raMid, |
| msgListenerType), false, |
| resourceAdapter.getClass().getClassLoader()).newInstance()); |
| aspec.setResourceAdapter(resourceAdapter); |
| |
| // Populate ActivationSpec class with ActivationConfig properties |
| SetMethodAction sma = |
| new SetMethodAction(aspec, activationConfigProps); |
| sma.run(); |
| activationSpecList.add(aspec); |
| } catch (Exception e) { |
| _logger.log(Level.WARNING, "error.creating.activationspec", e.getMessage()); |
| if (_logger.isLoggable(Level.FINE)) { |
| _logger.log(Level.FINE, e.toString(), e); |
| } |
| } |
| } |
| |
| // Get XA resources from RA. |
| |
| ActivationSpec[] activationSpecArray = activationSpecList.toArray(new ActivationSpec[activationSpecList.size()]); |
| XAResource[] xar = resourceAdapter.getXAResources(activationSpecArray); |
| |
| // Add the resources to the xaresList which is used by the RecoveryManager |
| if(xar != null){ |
| for (int p = 0; p < xar.length; p++) { |
| xaresList.add(xar[p]); |
| } |
| } |
| // Catch UnsupportedOperationException if a RA does not support XA |
| // which is fine. |
| } catch (UnsupportedOperationException uoex) { |
| _logger.log(Level.FINE, uoex.getMessage()); |
| // otherwise catch the unexpected exception |
| } catch (Exception e) { |
| _logger.log(Level.SEVERE, "exception.during.inbound.resource.acqusition", e); |
| } |
| } |
| } catch (Exception e) { |
| _logger.log(Level.SEVERE,"exception.during.inbound.recovery", e); |
| } |
| |
| } |
| |
| private Vector getEjbDescriptors(Application application, ApplicationRegistry appsRegistry) { |
| Vector ejbDescriptors = new Vector(); |
| |
| if(ResourcesUtil.createInstance().isEnabled(application)){ |
| ApplicationInfo appInfo = appsRegistry.get(application.getName()); |
| if(appInfo != null){ |
| com.sun.enterprise.deployment.Application app = |
| appInfo.getMetaData(com.sun.enterprise.deployment.Application.class); |
| Set<BundleDescriptor> descriptors = app.getBundleDescriptors(); |
| for (BundleDescriptor descriptor : descriptors) { |
| if (descriptor instanceof EjbBundleDescriptor) { |
| EjbBundleDescriptor ejbBundleDescriptor = (EjbBundleDescriptor) descriptor; |
| Set<? extends EjbDescriptor> ejbDescriptorsSet = ejbBundleDescriptor.getEjbs(); |
| for (EjbDescriptor ejbDescriptor : ejbDescriptorsSet) { |
| ejbDescriptors.add(ejbDescriptor); |
| } |
| } |
| } |
| }else{ |
| //application is enabled, but still not found in app-registry |
| _logger.log(Level.WARNING, "application.not.started.skipping.recovery", application.getName()); |
| } |
| } |
| return ejbDescriptors; |
| } |
| |
| private Map<String, List<EjbDescriptor>> createRAEjbMapping(List<EjbDescriptor> ejbDescriptors) { |
| |
| Map<String, List<EjbDescriptor>> map = new HashMap<String, List<EjbDescriptor>>(); |
| |
| for (EjbDescriptor ejbDescriptor : ejbDescriptors) { |
| List<EjbDescriptor> ejbmdbd = new ArrayList<EjbDescriptor>(); |
| String ramid = |
| ((EjbMessageBeanDescriptor) ejbDescriptor).getResourceAdapterMid(); |
| if ((ramid == null) || (ramid.equalsIgnoreCase(""))) { |
| ramid = ConnectorConstants.DEFAULT_JMS_ADAPTER; |
| } |
| |
| // If Hashtable contains the RAMid key, get the list of MDB descriptors |
| // and add the current MDB Descriptor (list[i]) to the list and put the |
| // pair back into hashtable. |
| // Otherwise, add the RAMid and the current MDB Descriptor to the hashtable |
| if (map.containsKey(ramid)) { |
| ejbmdbd = map.get(ramid); |
| map.remove(ramid); |
| } |
| |
| ejbmdbd.add(ejbDescriptor); |
| map.put(ramid, ejbmdbd); |
| } |
| return map; |
| } |
| |
| private void createActiveResourceAdapter(String rarModuleName) throws ConnectorRuntimeException { |
| |
| ConnectorRuntime cr = connectorRuntimeProvider.get(); |
| ConnectorRegistry creg = ConnectorRegistry.getInstance(); |
| |
| if (creg.isRegistered(rarModuleName)) |
| return; |
| |
| if (ConnectorAdminServiceUtils.isEmbeddedConnectorModule(rarModuleName)) { |
| cr.createActiveResourceAdapterForEmbeddedRar(rarModuleName); |
| } else { |
| String moduleDir ; |
| if (ConnectorsUtil.belongsToSystemRA(rarModuleName)) { |
| moduleDir = ConnectorsUtil.getSystemModuleLocation(rarModuleName); |
| }else{ |
| moduleDir = configBeansUtilities.getLocation(rarModuleName); |
| } |
| ClassLoader loader = cr.createConnectorClassLoader(moduleDir, null, rarModuleName); |
| cr.createActiveResourceAdapter(moduleDir, rarModuleName, loader); |
| } |
| } |
| |
| } |