org.glassfish.admin.amx.impl.j2ee.RegistrationSupport 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-2013 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 [2019] Payara Foundation and/or affiliates
package org.glassfish.admin.amx.impl.j2ee;
import com.sun.enterprise.config.serverbeans.ApplicationRef;
import com.sun.enterprise.config.serverbeans.BindableResource;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Resource;
import com.sun.enterprise.config.serverbeans.ResourcePool;
import com.sun.enterprise.config.serverbeans.ResourceRef;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.deployment.*;
import com.sun.enterprise.deployment.archivist.Archivist;
import com.sun.enterprise.deployment.archivist.ArchivistFactory;
import com.sun.enterprise.deployment.io.DeploymentDescriptorFile;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.*;
import org.glassfish.admin.amx.core.Util;
import org.glassfish.admin.amx.impl.config.ConfigBeanRegistry;
import org.glassfish.admin.amx.impl.j2ee.loader.J2EEInjectedValues;
import org.glassfish.admin.amx.impl.util.InjectedValues;
import org.glassfish.admin.amx.impl.util.ObjectNameBuilder;
import org.glassfish.admin.amx.j2ee.*;
import org.glassfish.admin.amx.util.ClassUtil;
import org.glassfish.admin.amx.util.MapUtil;
import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.api.admin.config.Named;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.ApplicationRegistry;
import org.jvnet.hk2.config.ConfigBeanProxy;
/**
Handles registrations of resources and applications associated with a J2EEServer.
There must be one and only one of these instances per J2EEServer.
*/
final class RegistrationSupport
{
private static void cdebug(Object o)
{
System.out.println("" + o);
}
/**
Associates the ObjectName of a ResourceRef or ApplicationRef with its corresponding
top-level JSR 77 MBean. Children of those JSR 77 MBeans come and go with their parent.
*/
private final Map mConfigRefTo77 = new HashMap();
private final J2EEServer mJ2EEServer;
private final MBeanServer mMBeanServer;
private final RefListener mResourceRefListener;
/** The Server config for this J2EEServer */
private final Server mServer;
/** type of any resource ref */
private final String mResourceRefType;
/** type of any application ref */
private final String mApplicationRefType;
private final Logger mLogger = AMXEELoggerInfo.getLogger();
public RegistrationSupport(final J2EEServer server)
{
mJ2EEServer = server;
mMBeanServer = (MBeanServer) server.extra().mbeanServerConnection();
mResourceRefType = Util.deduceType(ResourceRef.class);
mApplicationRefType = Util.deduceType(ApplicationRef.class);
mServer = getDomain().getServers().getServer( mJ2EEServer.getName() );
mResourceRefListener = new RefListener();
registerApplications();
}
protected void cleanup()
{
mResourceRefListener.stopListening();
}
public void start()
{
mResourceRefListener.startListening();
}
/** Maps configuration MBean type to J2EE type */
public static final Map CONFIG_RESOURCE_TYPES =
MapUtil.toMap(new Object[]
{
"jdbc-resource", JDBCResourceImpl.class,
"java-mail-resource", JavaMailResourceImpl.class,
"jca-resource", JCAResourceImpl.class,
"jms-resource", JMSResourceImpl.class,
"jndi-resource", JNDIResourceImpl.class,
"jta-resource", JTAResourceImpl.class,
"rmi-iiop-resource", RMI_IIOPResourceImpl.class,
"url-resource", URLResourceImpl.class
},
String.class, Class.class);
private Domain getDomain()
{
return InjectedValues.getInstance().getHabitat().getService(Domain.class);
}
private ObjectName getObjectName(ConfigBeanProxy cbp)
{
return ConfigBeanRegistry.getInstance().getObjectNameForProxy(cbp);
}
private String getDeploymentDescriptor(
final BundleDescriptor bundleDesc )
{
final ArchivistFactory archivistFactory = J2EEInjectedValues.getInstance().getArchivistFactory();
String dd = "unavailable";
ByteArrayOutputStream out = null;
try
{
final Archivist moduleArchivist = archivistFactory.getArchivist(bundleDesc.getModuleDescriptor().getModuleType());
final DeploymentDescriptorFile ddFile = moduleArchivist.getStandardDDFile();
out = new ByteArrayOutputStream();
ddFile.write(bundleDesc, out);
final String charsetName = "UTF-8";
dd = out.toString(charsetName);
}
catch( final Exception e )
{
dd = null;
}
finally
{
if ( out != null )
{
try { out.close(); } catch( Exception ee) {}
}
}
return dd;
}
private ObjectName createAppMBeans(
com.sun.enterprise.config.serverbeans.Application appConfig,
final Application application,
final MetadataImpl meta)
{
final String appLocation = appConfig.getLocation();
final boolean isStandalone = application.isVirtual();
ObjectName parentMBean = null;
ObjectName top = null;
if (isStandalone)
{
parentMBean = mJ2EEServer.objectName();
}
else
{
final String xmlDesc = getDeploymentDescriptor(application);
if ( xmlDesc != null )
{
meta.setDeploymentDescriptor(xmlDesc);
}
parentMBean = registerJ2EEChild(mJ2EEServer.objectName(), meta, J2EEApplication.class, J2EEApplicationImpl.class, application.getName());
top = parentMBean;
}
for (final EjbBundleDescriptor desc : application.getBundleDescriptors(EjbBundleDescriptor.class))
{
final ObjectName objectName = registerEjbModuleAndItsComponents(parentMBean, meta, appConfig, desc);
if (isStandalone)
{
assert (top == null);
top = objectName;
}
}
for (final WebBundleDescriptor desc : application.getBundleDescriptors(WebBundleDescriptor.class))
{
final ObjectName objectName = registerWebModuleAndItsComponents(parentMBean, meta, appConfig, desc);
if (isStandalone)
{
assert (top == null);
top = objectName;
}
}
for (final ConnectorDescriptor desc : application.getBundleDescriptors(ConnectorDescriptor.class))
{
assert top == null;
top = registerResourceAdapterModuleAndItsComponents(parentMBean, meta, appConfig, desc, appLocation);
}
for (final ApplicationClientDescriptor desc : application.getBundleDescriptors(ApplicationClientDescriptor.class))
{
assert top == null;
top = registerAppClient(parentMBean, meta, appConfig, desc);
}
mLogger.fine("Registered JSR 77 MBeans for application/module: " + top);
return top;
}
private com.sun.enterprise.config.serverbeans.Module
getModuleConfig( final com.sun.enterprise.config.serverbeans.Application appConfig, final String name)
{
if ( appConfig.getModule(name) == null )
{
throw new IllegalArgumentException( "Can't find module named " + name + " in " + appConfig );
}
return appConfig.getModule(name);
}
/* Register ejb module and its' children ejbs which is part of an application */
private ObjectName registerEjbModuleAndItsComponents(
final ObjectName parentMBean,
final MetadataImpl meta,
final com.sun.enterprise.config.serverbeans.Application appConfig,
final EjbBundleDescriptor ejbBundleDescriptor )
{
final String xmlDesc = getDeploymentDescriptor(ejbBundleDescriptor);
if ( xmlDesc != null )
{
meta.setDeploymentDescriptor( xmlDesc );
}
final String moduleName = ejbBundleDescriptor.getModuleName();
final com.sun.enterprise.config.serverbeans.Module moduleConfig = getModuleConfig(appConfig, moduleName );
meta.setCorrespondingConfig(getObjectName(moduleConfig));
final ObjectName ejbModuleObjectName = registerJ2EEChild(parentMBean, meta, EJBModule.class, EJBModuleImpl.class, moduleName);
meta.remove( Metadata.CORRESPONDING_CONFIG ); // none for an EJB MBean
meta.remove( Metadata.DEPLOYMENT_DESCRIPTOR ); // none for an EJB MBean
for (final EjbDescriptor desc : ejbBundleDescriptor.getEjbs())
{
createEJBMBean(ejbModuleObjectName, meta, desc);
}
return ejbModuleObjectName;
}
private ObjectName createEJBMBean(
final ObjectName parentMBean,
final MetadataImpl meta,
final EjbDescriptor ejbDescriptor)
{
final String ejbName = ejbDescriptor.getName();
final String ejbType = ejbDescriptor.getType();
final String ejbSessionType = ejbType.equals("Session") ? ((EjbSessionDescriptor) ejbDescriptor).getSessionType() : null;
Class extends EJB> intf = null;
Class extends EJBImplBase> impl = null;
if (ejbType.equals("Entity"))
{
intf = EntityBean.class;
impl = EntityBeanImpl.class;
}
else if (ejbType.equals("Message-driven"))
{
intf = MessageDrivenBean.class;
impl = MessageDrivenBeanImpl.class;
}
else if (ejbType.equals("Session"))
{
if ("Stateless".equals(ejbSessionType))
{
intf = StatelessSessionBean.class;
impl = StatelessSessionBeanImpl.class;
}
else if ("Stateful".equals(ejbSessionType))
{
intf = StatefulSessionBean.class;
impl = StatefulSessionBeanImpl.class;
}
else if ("Singleton".equals(ejbSessionType)) // EJB 3.1
{
intf = SingletonSessionBean.class;
impl = SingletonSessionBeanImpl.class;
}
else
{
throw new IllegalArgumentException("Unknown ejbSessionType: " + ejbSessionType + ", expected Stateless or Stateful");
}
} else {
throw new IllegalArgumentException("Unknown ejbType: " + ejbType + ", expected Entity, Message-driven or Session");
}
return registerJ2EEChild(parentMBean, meta, intf, impl, ejbName);
}
/* Register web module and its' children which is part of an application */
private ObjectName registerWebModuleAndItsComponents(
final ObjectName parentMBean,
final MetadataImpl meta,
final com.sun.enterprise.config.serverbeans.Application appConfig,
final WebBundleDescriptor webBundleDescriptor )
{
final String xmlDesc = getDeploymentDescriptor(webBundleDescriptor);
if ( xmlDesc != null )
{
meta.setDeploymentDescriptor( xmlDesc );
}
final String moduleName = webBundleDescriptor.getModuleName();
final com.sun.enterprise.config.serverbeans.Module moduleConfig = getModuleConfig(appConfig, moduleName );
meta.setCorrespondingConfig(getObjectName(moduleConfig));
final ObjectName webModuleObjectName = registerJ2EEChild(parentMBean, meta, WebModule.class, WebModuleImpl.class, moduleName);
meta.remove( Metadata.CORRESPONDING_CONFIG ); // none for a Servlet
meta.remove( Metadata.DEPLOYMENT_DESCRIPTOR ); // none for an Servlet
for (final WebComponentDescriptor desc : webBundleDescriptor.getWebComponentDescriptors())
{
final String servletName = desc.getCanonicalName();
registerJ2EEChild(webModuleObjectName, meta, Servlet.class, ServletImpl.class, servletName);
}
return webModuleObjectName;
}
public ObjectName registerResourceAdapterModuleAndItsComponents(
final ObjectName parentMBean,
final MetadataImpl meta,
final com.sun.enterprise.config.serverbeans.Application appConfig,
final ConnectorDescriptor bundleDesc,
final String appLocation)
{
meta.setCorrespondingConfig(getObjectName(appConfig));
final ObjectName objectName = createRARModuleMBean(parentMBean, meta, appConfig, bundleDesc);
final com.sun.enterprise.config.serverbeans.Module moduleConfig = getModuleConfig(appConfig, bundleDesc.getModuleName() );
meta.setCorrespondingConfig(getObjectName(moduleConfig));
registerJ2EEChild(objectName, meta, ResourceAdapter.class, ResourceAdapterImpl.class, bundleDesc.getName());
return objectName;
}
private ObjectName createRARModuleMBean(
final ObjectName parentMBean,
final MetadataImpl meta,
final com.sun.enterprise.config.serverbeans.Application appConfig,
final ConnectorDescriptor bundleDesc )
{
final String xmlDesc = getDeploymentDescriptor(bundleDesc);
if ( xmlDesc != null )
{
meta.setDeploymentDescriptor( xmlDesc );
}
final String resAdName = bundleDesc.getModuleName();
final ObjectName objectName = registerJ2EEChild(parentMBean, meta, ResourceAdapterModule.class, ResourceAdapterModuleImpl.class, resAdName);
return objectName;
}
/* Register application client module */
public ObjectName registerAppClient(
final ObjectName parentMBean,
final MetadataImpl meta,
final com.sun.enterprise.config.serverbeans.Application appConfig,
final ApplicationClientDescriptor bundleDesc)
{
final String xmlDesc = getDeploymentDescriptor(bundleDesc);
if ( xmlDesc != null )
{
meta.setDeploymentDescriptor( xmlDesc );
}
final String moduleName = bundleDesc.getModuleDescriptor().getModuleName();
return registerJ2EEChild(parentMBean, meta, AppClientModule.class, AppClientModuleImpl.class, moduleName);
}
protected void registerApplications()
{
final List appRefs = mServer.getApplicationRef();
for (final ApplicationRef ref : appRefs)
{
try
{
processApplicationRef(ref);
}
catch( final Exception e )
{
// log it: we want to continue with other apps, even if this one had a problem
mLogger.log( Level.INFO, AMXEELoggerInfo.registeringApplicationException,
new Object[] { ref.getRef(), e});
}
}
}
/**
Examine the MBean to see if it is a ResourceRef that should be manifested under this server,
and if so, register a JSR 77 MBean for it.
*/
public ObjectName processApplicationRef(final ApplicationRef ref)
{
// find all applications
final ApplicationRegistry appRegistry = J2EEInjectedValues.getInstance().getApplicationRegistry();
final MetadataImpl meta = new MetadataImpl();
meta.setCorrespondingRef(getObjectName(ref));
final String appName = ref.getRef();
final ApplicationInfo appInfo = appRegistry.get(appName);
if (appInfo == null)
{
mLogger.fine("Unable to get ApplicationInfo for application: " + appName);
return null;
}
final Application app = appInfo.getMetaData(Application.class);
if ( app == null )
{
if ( appInfo.isJavaEEApp() )
{
mLogger.log(Level.WARNING, AMXEELoggerInfo.nullAppinfo, appName);
}
return null;
}
final com.sun.enterprise.config.serverbeans.Application appConfig = getDomain().getApplications().getApplication(appName);
if ( appConfig == null )
{
mLogger.log(Level.WARNING, AMXEELoggerInfo.errorGetappconfig, appName);
return null;
}
meta.setCorrespondingConfig( getObjectName(appConfig) );
final ObjectName mbean77 = createAppMBeans(appConfig, app, meta);
synchronized (mConfigRefTo77)
{
mConfigRefTo77.put(getObjectName(ref), mbean77);
}
return mbean77;
}
protected ObjectName registerJ2EEChild(
final ObjectName parent,
final Metadata metadataIn,
final Class intf,
final Class clazz,
final String name)
{
ObjectName objectName = null;
final String j2eeType = Util.deduceType(intf);
// must make a copy! May be an input value that is reused by caller
final Metadata metadata = new MetadataImpl(metadataIn);
try
{
final Constructor c = clazz.getConstructor(ObjectName.class, Metadata.class);
final J2EEManagedObjectImplBase impl = c.newInstance(parent, metadata);
objectName = new ObjectNameBuilder(mMBeanServer, parent).buildChildObjectName(j2eeType, name);
objectName = mMBeanServer.registerMBean( impl, objectName ).getObjectName();
}
catch (final Exception e)
{
throw new RuntimeException( "Cannot register " + j2eeType + "=" + name + " as child of " + parent, e);
}
return objectName;
}
/**
Examine the MBean to see if it is a ResourceRef that should be manifested under this server,
and if so, register a JSR 77 MBean for it.
*/
public ObjectName processResourceRef(final ResourceRef ref)
{
if (ref == null)
{
throw new IllegalArgumentException("resource-ref is null");
}
if ( ! mServer.getName().equals(ref.getParent(Server.class).getName()))
{
cdebug("ResourceRef is not a child of server " + getObjectName(mServer));
return null;
}
// find the referenced resource
Resource res = null;
List resources = getDomain().getResources().getResources();
for (Resource resource : resources)
{
String name = null;
if (resource instanceof BindableResource) {
name = ((BindableResource) resource).getJndiName();
}
if (resource instanceof Named) {
name = ((Named) resource).getName();
}
if (resource instanceof ResourcePool) {
name = ((ResourcePool) resource).getName();
}
if (name != null && name.equals(ref.getRef()))
res = resource;
}
if (res == null)
{
throw new IllegalArgumentException("ResourceRef refers to non-existent resource: " + ref);
}
final String configType = Util.getTypeProp(getObjectName(res));
final Class implClass = CONFIG_RESOURCE_TYPES.get(configType);
if (implClass == null)
{
mLogger.fine("Unrecognized resource type for JSR 77 purposes: " + getObjectName(res));
return null;
}
final Class intf = (Class) ClassUtil.getFieldValue(implClass, "INTF");
ObjectName mbean77 = null;
try
{
final MetadataImpl meta = new MetadataImpl();
meta.setCorrespondingRef(getObjectName(ref));
meta.setCorrespondingConfig(getObjectName(res));
mbean77 = registerJ2EEChild(mJ2EEServer.objectName(), meta, intf, implClass, Util.getNameProp(getObjectName(res)));
synchronized (mConfigRefTo77)
{
mConfigRefTo77.put(getObjectName(ref), mbean77);
}
}
catch (final Exception e)
{
mLogger.log( Level.INFO, AMXEELoggerInfo.cantRegisterMbean, new Object[] { getObjectName(ref), e });
}
//cdebug( "Registered " + child + " for config resource " + amx.objectName() );
return mbean77;
}
/**
Listen for registration/unregistration of {@link ResourceRef},
and associate them with JSR 77 MBeans for this J2EEServer.
Resources belong to a J2EEServer via ResourceRefs. So we can stay in the AMX
world by tracking registration and unregistration of AMX config MBeans of
type ResourceRef.
*/
private final class RefListener implements NotificationListener
{
public RefListener()
{
}
public void handleNotification(final Notification notifIn, final Object handback)
{
if (!(notifIn instanceof MBeanServerNotification))
{
return;
}
final MBeanServerNotification notif = (MBeanServerNotification) notifIn;
final ObjectName objectName = notif.getMBeanName();
if ( ! mJ2EEServer.objectName().getDomain().equals(objectName.getDomain()))
{
return;
}
final String type = Util.getTypeProp(objectName);
if (notif.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
{
if ( type.equals( mResourceRefType ) )
{
mLogger.fine("New ResourceRef MBEAN registered: " + objectName);
final ResourceRef ref = (ResourceRef) ConfigBeanRegistry.getInstance().getConfigBean(objectName);
processResourceRef(ref);
}
else if ( type.equals( mApplicationRefType ) )
{
mLogger.fine( "NEW ApplicationRef MBEAN registered: " + objectName);
final ApplicationRef ref = (ApplicationRef) ConfigBeanRegistry.getInstance().getConfigBean(objectName);
processApplicationRef(ref);
}
}
else if (notif.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
{
// determine if it's a config for which a JSR 77 MBean is registered
synchronized (mConfigRefTo77)
{
final ObjectName mbean77 = mConfigRefTo77.remove(objectName);
if (mbean77 != null)
{
mLogger.fine( "Unregistering MBEAN for ref: " + objectName);
try
{
mMBeanServer.unregisterMBean(mbean77);
}
catch (final Exception e)
{
mLogger.log( Level.WARNING, AMXEELoggerInfo.cantUnregisterMbean, objectName);
mLogger.log( Level.WARNING, null, e);
}
}
}
}
}
public void startListening()
{
// important: processResourceRef a listener *first* so that we don't miss anything
try
{
mMBeanServer.addNotificationListener(JMXUtil.getMBeanServerDelegateObjectName(), this, null, null);
}
catch (final JMException e)
{
throw new RuntimeException(e);
}
// register all existing
final List resourceRefs = mServer.getResourceRef();
for (final ResourceRef ref : resourceRefs)
{
processResourceRef(ref);
}
}
public void stopListening()
{
try
{
mMBeanServer.removeNotificationListener(JMXUtil.getMBeanServerDelegateObjectName(), this);
}
catch (final JMException e)
{
throw new RuntimeException(e);
}
}
}
}