| /* |
| * Copyright (c) 1998, 2021 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, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| // @author mobrien |
| // @since EclipseLink 1.0 enh# 235168 |
| package org.eclipse.persistence.services; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| import java.util.Vector; |
| import java.util.regex.PatternSyntaxException; |
| |
| import javax.management.openmbean.CompositeData; |
| import javax.management.openmbean.CompositeDataSupport; |
| import javax.management.openmbean.CompositeType; |
| import javax.management.openmbean.OpenDataException; |
| import javax.management.openmbean.OpenType; |
| import javax.management.openmbean.SimpleType; |
| import javax.management.openmbean.TabularData; |
| import javax.management.openmbean.TabularDataSupport; |
| import javax.management.openmbean.TabularType; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor; |
| import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform; |
| import org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform; |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.internal.helper.Helper; |
| import org.eclipse.persistence.internal.identitymaps.CacheIdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.CacheKey; |
| import org.eclipse.persistence.internal.identitymaps.FullIdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.HardCacheWeakIdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.IdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.NoIdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.SoftCacheWeakIdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.SoftIdentityMap; |
| import org.eclipse.persistence.internal.identitymaps.WeakIdentityMap; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl; |
| import org.eclipse.persistence.logging.AbstractSessionLog; |
| import org.eclipse.persistence.logging.DefaultSessionLog; |
| import org.eclipse.persistence.logging.JavaLog; |
| import org.eclipse.persistence.logging.SessionLog; |
| import org.eclipse.persistence.platform.server.JMXEnabledPlatform; |
| import org.eclipse.persistence.sessions.DatabaseLogin; |
| import org.eclipse.persistence.sessions.DefaultConnector; |
| import org.eclipse.persistence.sessions.Session; |
| import org.eclipse.persistence.sessions.server.ConnectionPool; |
| import org.eclipse.persistence.sessions.server.ServerSession; |
| import org.eclipse.persistence.tools.profiler.PerformanceProfiler; |
| |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: Provide a dynamic interface into the EclipseLink Session. |
| * <p> |
| * <b>Description</b>: This class is meant to provide a framework for gaining access to configuration |
| * of the EclipseLink Session during runtime. It will provide the basis for development |
| * of a JMX service and possibly other frameworks. |
| * |
| */ |
| public abstract class RuntimeServices { |
| |
| /** stores access to the session object that we are controlling */ |
| protected Session session; |
| |
| /** This is the profile weight at server startup time. This is read-only */ |
| private int deployedSessionProfileWeight; |
| |
| /** This contains the session log from server startup time. This is read-only. */ |
| private SessionLog deployedSessionLog; |
| |
| public String objectName; |
| |
| protected static final String EclipseLink_Product_Name = "EclipseLink"; |
| /** Short name for the server platform - Must override in subclass */ |
| protected static String PLATFORM_NAME = "Server"; |
| |
| /** |
| * Default Constructor |
| */ |
| protected RuntimeServices() { |
| } |
| |
| /** |
| * Constructor |
| * @param session the session to be used with these RuntimeServices |
| */ |
| protected RuntimeServices(Session session) { |
| this.session = session; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| protected AbstractSession getSession() { |
| return (AbstractSession)this.session; |
| } |
| |
| /** |
| * Answer the name of the EclipseLink session this MBean represents. |
| */ |
| public String getSessionName() { |
| return getSession().getName(); |
| } |
| |
| /** |
| * This method is used to determine if logging is turned on |
| */ |
| public boolean getShouldLogMessages() { |
| return getSession().shouldLogMessages(); |
| } |
| |
| /** |
| * This method is used to turn on Performance Profiling |
| */ |
| public void setShouldProfilePerformance(boolean shouldProfile) { |
| if (shouldProfile && (getSession().getProfiler() == null)) { |
| getSession().setProfiler(new PerformanceProfiler()); |
| } else if (!shouldProfile) { |
| getSession().setProfiler(null); |
| } |
| } |
| |
| /** |
| * This method will return if profiling is turned on or not |
| */ |
| public boolean getShouldProfilePerformance() { |
| return (getSession().getProfiler() != null) && ClassConstants.PerformanceProfiler_Class.isAssignableFrom(getSession().getProfiler().getClass()); |
| } |
| |
| /** |
| * This method is used to turn on Profile logging when using the Performance Profiler |
| */ |
| public void setShouldLogPerformanceProfiler(boolean shouldLogPerformanceProfiler) { |
| if ((getSession().getProfiler() != null) && ClassConstants.PerformanceProfiler_Class.isAssignableFrom(getSession().getProfiler().getClass())) { |
| ((PerformanceProfiler)getSession().getProfiler()).setShouldLogProfile(shouldLogPerformanceProfiler); |
| } |
| } |
| |
| /** |
| * Method indicates if Performance profile should be logged |
| */ |
| public boolean getShouldLogPerformanceProfiler() { |
| if ((getSession().getProfiler() != null) && ClassConstants.PerformanceProfiler_Class.isAssignableFrom(getSession().getProfiler().getClass())) { |
| return ((PerformanceProfiler)getSession().getProfiler()).shouldLogProfile(); |
| } |
| return false; |
| } |
| |
| /** |
| * Method used to set if statements should be cached. Please note that Statements can not be cached when |
| * using an external connection pool |
| */ |
| public void setShouldCacheAllStatements(boolean shouldCacheAllStatements) { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return; |
| } |
| ((DatabaseLogin)getSession().getDatasourceLogin()).setShouldCacheAllStatements(shouldCacheAllStatements); |
| } |
| |
| /** |
| * Used to set the statement cache size. This is only valid if using cached Statements |
| */ |
| public void setStatementCacheSize(int size) { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return; |
| } |
| ((DatabaseLogin)getSession().getDatasourceLogin()).setStatementCacheSize(size); |
| } |
| |
| /** |
| * Returns the statement cache size. Only valid if statements are being cached |
| */ |
| public int getStatementCacheSize() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return 0; |
| } |
| return ((DatabaseLogin)getSession().getDatasourceLogin()).getStatementCacheSize(); |
| } |
| |
| /** |
| * This method provide access for setting the sequence pre-allocation size |
| */ |
| public void setSequencePreallocationSize(int size) { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return; |
| } |
| ((DatasourcePlatform)getSession().getDatasourcePlatform()).setSequencePreallocationSize(size); |
| } |
| |
| /** |
| * Method returns the value of the Sequence Preallocation size |
| */ |
| public int getSequencePreallocationSize() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return 0; |
| } |
| return ((DatasourcePlatform)getSession().getDatasourcePlatform()).getSequencePreallocationSize(); |
| } |
| |
| /** |
| * This method allows the client to set the pool size for a particular pool, based on the pool name |
| * @param poolName the name of the pool to be updated. |
| * @param maxSize the new maximum number of connections |
| * @param minSize the new minimum number of connections |
| */ |
| public void updatePoolSize(String poolName, int maxSize, int minSize) { |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| ConnectionPool connectionPool = ((ServerSession)getSession()).getConnectionPool(poolName); |
| if (connectionPool != null) { |
| connectionPool.setMaxNumberOfConnections(maxSize); |
| connectionPool.setMinNumberOfConnections(minSize); |
| } |
| } |
| } |
| |
| /** |
| * This method will return the available Connection pools within this Server Session |
| * @return java.util.List the available pools. |
| */ |
| public List getAvailableConnectionPools() { |
| Vector list = null; |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| Map<String, ConnectionPool> pools = ((ServerSession)getSession()).getConnectionPools(); |
| list = new Vector(pools.size()); |
| Iterator<String> poolNames = pools.keySet().iterator(); |
| while (poolNames.hasNext()) { |
| list.add(poolNames.next()); |
| } |
| } else { |
| list = new Vector(); |
| } |
| return list; |
| } |
| |
| /** |
| * This method will retrieve the size of a particular connection pool |
| * @param poolName the name of the pool to get the size for |
| * @return java.util.List a list containing two values. The first value is the Maximun size of the pool. |
| * The second value is the Minimum size of the pool. |
| */ |
| public List getSizeForPool(String poolName) { |
| Vector results = new Vector(2); |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| ConnectionPool connectionPool = ((ServerSession)getSession()).getConnectionPool(poolName); |
| if (connectionPool != null) { |
| results.add(connectionPool.getMaxNumberOfConnections()); |
| results.add(connectionPool.getMinNumberOfConnections()); |
| } |
| } |
| return results; |
| } |
| |
| /** |
| * This method provides client with access to add a new connection pool to a EclipseLink |
| * ServerSession. |
| * @param poolName the name of the new pool |
| * @param maxSize the maximum number of connections in the pool |
| * @param minSize the minimum number of connections in the pool |
| * @param platform the fully qualified name of the EclipseLink platform to use with this pool. |
| * @param driverClassName the fully qualified name of the JDBC driver class |
| * @param url the URL of the database to connect to |
| * @param userName the user name to connect to the database with |
| * @param password the password to connect to the database with |
| * @exception ClassNotFoundException if any of the class names are misspelled. |
| */ |
| public void addNewConnectionPool(String poolName, int maxSize, int minSize, String platform, String driverClassName, String url, String userName, String password) throws ClassNotFoundException { |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| DatabaseLogin login = new DatabaseLogin(); |
| login.setPlatformClassName(platform); |
| login.setDriverClassName(driverClassName); |
| login.setConnectionString(url); |
| login.setUserName(userName); |
| login.setEncryptedPassword(password); |
| ((ServerSession)getSession()).addConnectionPool(poolName, login, minSize, maxSize); |
| } |
| } |
| |
| /** |
| * This method is used to reset connections from the session to the database. Please |
| * Note that this will not work with a SessionBroker at this time |
| */ |
| public void resetAllConnections() { |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| Iterator<ConnectionPool> enumtr = ((ServerSession)getSession()).getConnectionPools().values().iterator(); |
| while (enumtr.hasNext()) { |
| ConnectionPool pool = enumtr.next(); |
| pool.shutDown(); |
| pool.startUp(); |
| } |
| } else if (ClassConstants.PublicInterfaceDatabaseSession_Class.isAssignableFrom(getSession().getClass())) { |
| getSession().getAccessor().reestablishConnection(getSession()); |
| } |
| } |
| |
| /** |
| * This method is used to return those Class Names that have identity Maps in the Session. |
| * Please note that SubClasses and aggregates will be missing form this list as they do not have |
| * separate identity maps. |
| * @return java.util.List contains all of the classes which have identity maps in the current session. |
| */ |
| public List getClassesInSession() { |
| return getSession().getIdentityMapAccessorInstance().getIdentityMapManager().getClassesRegistered(); |
| } |
| |
| /** |
| * This method will return a collection of the objects in the Identity Map. |
| * There is no particular order to these objects. |
| * @param className the fully qualified classname of the class to the instances of |
| * @exception ClassNotFoundException thrown then the IdentityMap for that class name could not be found |
| */ |
| public List getObjectsInIdentityMap(String className) throws ClassNotFoundException { |
| Class classToChange = getSession().getDatasourcePlatform().getConversionManager().convertObject(className, ClassConstants.CLASS); |
| IdentityMap map = getSession().getIdentityMapAccessorInstance().getIdentityMap(classToChange); |
| |
| Vector results = new Vector(map.getSize()); |
| Enumeration<CacheKey> objects = map.keys(); |
| while (objects.hasMoreElements()) { |
| results.add(objects.nextElement().getObject()); |
| } |
| return results; |
| } |
| |
| /** |
| * This method is used to return the number of objects in a particular Identity Map |
| * @param className the fully qualified name of the class to get number of instances of. |
| * @exception ClassNotFoundException thrown then the IdentityMap for that class name could not be found |
| */ |
| public Integer getNumberOfObjectsInIdentityMap(String className) throws ClassNotFoundException { |
| Class classToChange = getSession().getDatasourcePlatform().getConversionManager().convertObject(className, ClassConstants.CLASS); |
| return getSession().getIdentityMapAccessorInstance().getIdentityMap(classToChange).getSize(); |
| } |
| |
| /** |
| * This method is used to return a Map of the objects in a particular Identity Map's |
| * subcache. Only works for those identity Maps with a sub cache (ie Hard Cache Weak Identity Map) |
| * This method replaces getObjectsInIdentityMapSubCache(className) which returns a list instead |
| * of a Map |
| * @param className the fully qualified name of the class to get number of instances of. |
| * @exception ClassNotFoundException thrown then the IdentityMap for that class name could not be found |
| */ |
| public List getObjectsInIdentityMapSubCacheAsMap(String className) throws ClassNotFoundException { |
| Class classToChange = getSession().getDatasourcePlatform().getConversionManager().convertObject(className, ClassConstants.CLASS); |
| IdentityMap map = getSession().getIdentityMapAccessorInstance().getIdentityMap(classToChange); |
| |
| //CR3855 |
| List subCache = new ArrayList(0); |
| if (ClassConstants.HardCacheWeakIdentityMap_Class.isAssignableFrom(map.getClass())) { |
| subCache = ((HardCacheWeakIdentityMap)map).getReferenceCache(); |
| } |
| return subCache; |
| } |
| |
| /** |
| * This method is used to return the number of objects in a particular Identity Map's |
| * subcache. Only works for those identity Maps with a sub cache (ie Hard Cache Weak Identity Map) |
| * @param className the fully qualified name of the class to get number of instances of. |
| * @exception ClassNotFoundException thrown then the IdentityMap for that class name could not be found |
| */ |
| public Integer getNumberOfObjectsInIdentityMapSubCache(String className) throws ClassNotFoundException { |
| //This needs to use the Session's active class loader (not implemented yet) |
| Integer result = 0; |
| Class classToChange = getSession().getDatasourcePlatform().getConversionManager().convertObject(className, ClassConstants.CLASS); |
| IdentityMap map = getSession().getIdentityMapAccessorInstance().getIdentityMap(classToChange); |
| if (map.getClass().isAssignableFrom(ClassConstants.HardCacheWeakIdentityMap_Class)) { |
| List subCache = ((HardCacheWeakIdentityMap)map).getReferenceCache(); |
| result = subCache.size(); |
| } |
| return result; |
| } |
| |
| /** |
| * <p> |
| * Return the log level |
| * </p> |
| * @param category the string representation of an EclipseLink category, e.g. "sql", "transaction" ... |
| * @return the log level |
| */ |
| public int getLogLevel(String category) { |
| return getSession().getLogLevel(category); |
| } |
| |
| /** |
| * <p> |
| * Set the log level |
| * </p> |
| * |
| * @param level the new log level |
| */ |
| public void setLogLevel(int level) { |
| getSession().setLogLevel(level); |
| } |
| |
| /** |
| * <p> |
| * Check if a message of the given level would actually be logged. |
| * </p> |
| * |
| * @param Level the log request level |
| * @param category the string representation of an EclipseLink category |
| * @return true if the given message level will be logged |
| */ |
| public boolean shouldLog(int Level, String category) { |
| return getSession().shouldLog(Level, category); |
| } |
| |
| /** |
| * Return the DMS sensor weight |
| */ |
| public int getProfileWeight() { |
| if (getSession().isInProfile()) { |
| return getSession().getProfiler().getProfileWeight(); |
| } else { |
| return 0; |
| } |
| } |
| |
| /** |
| * This method is used to change DMS sensor weight. |
| */ |
| public void setProfileWeight(int weight) { |
| if (getSession().isInProfile()) { |
| getSession().getProfiler().setProfileWeight(weight); |
| } |
| } |
| |
| /** |
| * This method is used to initialize the identity maps specified by className. |
| * @param className the fully qualified classnames identifying the identity map to initialize |
| */ |
| public synchronized void initializeIdentityMap(String className) throws ClassNotFoundException { |
| Class registeredClass; |
| |
| //get identity map, and initialize |
| registeredClass = getSession().getDatasourcePlatform().getConversionManager() |
| .convertObject(className, ClassConstants.CLASS); |
| getSession().getIdentityMapAccessor().initializeIdentityMap(registeredClass); |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_identity_map_initialized", className); |
| } |
| |
| /** |
| * This method will log the instance level locks in all Identity Maps in the session. |
| */ |
| public void printIdentityMapLocks() { |
| getSession().getIdentityMapAccessorInstance().getIdentityMapManager().printLocks(); |
| } |
| |
| /** |
| * This method will log the instance level locks in the Identity Map for the given class in the session. |
| */ |
| public void printIdentityMapLocks(String registeredClassName) { |
| Class registeredClass = getSession().getDatasourcePlatform().getConversionManager() |
| .convertObject(registeredClassName, ClassConstants.CLASS); |
| getSession().getIdentityMapAccessorInstance().getIdentityMapManager().printLocks(registeredClass); |
| } |
| |
| /** |
| * This method assumes EclipseLink Profiling (as opposed to Java profiling). |
| * This will log at the INFO level a summary of all elements in the profile. |
| */ |
| public void printProfileSummary() { |
| if (!this.getUsesEclipseLinkProfiling()) { |
| return; |
| } |
| PerformanceProfiler performanceProfiler = (PerformanceProfiler)getSession().getProfiler(); |
| getSession().getSessionLog().info(performanceProfiler.buildProfileSummary().toString()); |
| } |
| |
| /** |
| * INTERNAL: |
| * utility method to get rid of leading and trailing {}'s |
| */ |
| private String trimProfileString(String originalProfileString) { |
| String trimmedString; |
| |
| if (originalProfileString.length() > 1) { |
| trimmedString = originalProfileString.substring(0, originalProfileString.length()); |
| if ((trimmedString.charAt(0) == '{') && (trimmedString.charAt(trimmedString.length() - 1) == '}')) { |
| trimmedString = trimmedString.substring(1, trimmedString.length() - 1); |
| } |
| return trimmedString; |
| } else { |
| return originalProfileString; |
| } |
| } |
| |
| /** |
| * This method assumes EclipseLink Profiling (as opposed to Java profiling). |
| * This will log at the INFO level a summary of all elements in the profile, categorized |
| * by Class. |
| */ |
| public void printProfileSummaryByClass() { |
| if (!this.getUsesEclipseLinkProfiling()) { |
| return; |
| } |
| PerformanceProfiler performanceProfiler = (PerformanceProfiler)getSession().getProfiler(); |
| //trim the { and } from the beginning at end, because they cause problems for the logger |
| getSession().getSessionLog().info(trimProfileString(performanceProfiler.buildProfileSummaryByClass().toString())); |
| } |
| |
| /** |
| * This method assumes EclipseLink Profiling (as opposed to Java profiling). |
| * This will log at the INFO level a summary of all elements in the profile, categorized |
| * by Query. |
| */ |
| public void printProfileSummaryByQuery() { |
| if (!this.getUsesEclipseLinkProfiling()) { |
| return; |
| } |
| PerformanceProfiler performanceProfiler = (PerformanceProfiler)getSession().getProfiler(); |
| getSession().getSessionLog().info(trimProfileString(performanceProfiler.buildProfileSummaryByQuery().toString())); |
| } |
| |
| /** |
| * This method is used to get the type of profiling. |
| * Possible values are: "EclipseLink" or "None". |
| */ |
| public synchronized String getProfilingType() { |
| if (getUsesEclipseLinkProfiling()) { |
| return EclipseLink_Product_Name; |
| } else { |
| return "None"; |
| } |
| } |
| |
| /** |
| * This method is used to select the type of profiling. |
| * Valid values are: "EclipseLink" or "None". These values are not case sensitive. |
| * null is considered to be "None". |
| */ |
| public synchronized void setProfilingType(String profileType) { |
| if ((profileType == null) || (profileType.compareToIgnoreCase("None") == 0)) { |
| this.setUseNoProfiling(); |
| } else if (profileType.compareToIgnoreCase(EclipseLink_Product_Name) == 0) { |
| this.setUseEclipseLinkProfiling(); |
| } |
| } |
| |
| /** |
| * This method is used to turn on EclipseLink Performance Profiling |
| */ |
| public void setUseEclipseLinkProfiling() { |
| if (getUsesEclipseLinkProfiling()) { |
| return; |
| } |
| getSession().setProfiler(new PerformanceProfiler()); |
| } |
| |
| |
| /** |
| * This method is used to turn off all Performance Profiling, DMS or EclipseLink. |
| */ |
| public void setUseNoProfiling() { |
| getSession().setProfiler(null); |
| } |
| |
| /** |
| * This method answers true if EclipseLink Performance Profiling is on. |
| */ |
| public Boolean getUsesEclipseLinkProfiling() { |
| return getSession().getProfiler() instanceof PerformanceProfiler; |
| } |
| |
| /** |
| * PUBLIC: Answer the EclipseLink log level at deployment time. This is read-only. |
| */ |
| public String getDeployedEclipseLinkLogLevel() { |
| return getNameForLogLevel(getDeployedSessionLog().getLevel()); |
| } |
| |
| /** |
| * PUBLIC: Answer the EclipseLink log level that is changeable. |
| * This does not affect the log level in the project (i.e. The next |
| * time the application is deployed, changes are forgotten) |
| */ |
| public String getCurrentEclipseLinkLogLevel() { |
| return getNameForLogLevel(this.getSession().getSessionLog().getLevel()); |
| } |
| |
| /** |
| * PUBLIC: Set the EclipseLink log level to be used at runtime. |
| * |
| * This does not affect the log level in the project (i.e. The next |
| * time the application is deployed, changes are forgotten) |
| * |
| * @param newLevel new log level |
| */ |
| public synchronized void setCurrentEclipseLinkLogLevel(String newLevel) { |
| this.getSession().setLogLevel(this.getLogLevelForName(newLevel)); |
| } |
| |
| /** |
| * INTERNAL: Answer the name for the log level given. |
| * |
| * @return String (one of OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL) |
| */ |
| private String getNameForLogLevel(int logLevel) { |
| switch (logLevel) { |
| case SessionLog.ALL: |
| return SessionLog.ALL_LABEL; |
| case SessionLog.SEVERE: |
| return SessionLog.SEVERE_LABEL; |
| case SessionLog.WARNING: |
| return SessionLog.WARNING_LABEL; |
| case SessionLog.INFO: |
| return SessionLog.INFO_LABEL; |
| case SessionLog.CONFIG: |
| return SessionLog.CONFIG_LABEL; |
| case SessionLog.FINE: |
| return SessionLog.FINE_LABEL; |
| case SessionLog.FINER: |
| return SessionLog.FINER_LABEL; |
| case SessionLog.FINEST: |
| return SessionLog.FINEST_LABEL; |
| case SessionLog.OFF: |
| return SessionLog.OFF_LABEL; |
| default: |
| return "N/A"; |
| } |
| } |
| |
| /** |
| * INTERNAL: Answer the log level for the given name. |
| * |
| * @return int for OFF, SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, ALL |
| */ |
| private int getLogLevelForName(String levelName) { |
| if (levelName.equals(SessionLog.ALL_LABEL)) { |
| return SessionLog.ALL; |
| } |
| if (levelName.equals(SessionLog.SEVERE_LABEL)) { |
| return SessionLog.SEVERE; |
| } |
| if (levelName.equals(SessionLog.WARNING_LABEL)) { |
| return SessionLog.WARNING; |
| } |
| if (levelName.equals(SessionLog.INFO_LABEL)) { |
| return SessionLog.INFO; |
| } |
| if (levelName.equals(SessionLog.CONFIG_LABEL)) { |
| return SessionLog.CONFIG; |
| } |
| if (levelName.equals(SessionLog.FINE_LABEL)) { |
| return SessionLog.FINE; |
| } |
| if (levelName.equals(SessionLog.FINER_LABEL)) { |
| return SessionLog.FINER; |
| } |
| if (levelName.equals(SessionLog.FINEST_LABEL)) { |
| return SessionLog.FINEST; |
| } |
| return SessionLog.OFF; |
| } |
| /** |
| * INTERNAL: |
| * Define the deployment time data associated with logging and profiling |
| * |
| */ |
| protected void updateDeploymentTimeData() { |
| this.deployedSessionLog = (SessionLog) session.getSessionLog().clone(); |
| if (session.getProfiler() == null) { |
| this.deployedSessionProfileWeight = -1;//there is no profiler |
| } else { |
| this.deployedSessionProfileWeight = session.getProfiler().getProfileWeight(); |
| } |
| } |
| |
| public int getDeployedSessionProfileWeight() { |
| return deployedSessionProfileWeight; |
| } |
| |
| public SessionLog getDeployedSessionLog() { |
| return deployedSessionLog; |
| } |
| |
| public String getObjectName() { |
| return objectName; |
| } |
| |
| /** |
| * Return whether this session is an EclipseLink JPA session. |
| * The absence of this function or a value of false will signify that the session |
| * belongs to a provider other than EclipseLink. |
| */ |
| public boolean isJPASession() { |
| return true; |
| } |
| |
| /** |
| * Answer the type of the EclipseLink session this MBean represents. |
| * Types include: "ServerSession", "DatabaseSession", "SessionBroker" |
| */ |
| public String getSessionType() { |
| return Helper.getShortClassName(getSession().getClass()); |
| } |
| |
| /** |
| * Provide an instance of 2 Dimensional Array simulating tabular format information about all |
| * classes in the session whose class names match the provided filter. |
| * |
| * The 2 Dimensional array contains each item with values being row object array. Each row object array |
| * represents EclipseLink class details info with respect to below attributes: |
| * ["Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size"] |
| * |
| */ |
| public Object[][] getClassSummaryDetailsUsingFilter(String filter){ |
| try{ |
| return tabularDataTo2DArray(buildClassSummaryDetailsUsingFilter(filter),new String[] { |
| "Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size" }); |
| } catch (Exception exception) { |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, exception); |
| } |
| return null; |
| } |
| |
| /** |
| * PUBLIC: Provide an instance of 2 Dimensional Array simulating tabular format information about all |
| * classes in the session. |
| * |
| * The 2 Dimensional array contains each item with values being row object array. Each row object array |
| * represents EclipseLink class details info with respect to below attributes: |
| * ["Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size"] |
| * |
| */ |
| public Object[][] getClassSummaryDetails() { |
| try{ |
| return tabularDataTo2DArray(buildClassSummaryDetails(),new String[] { |
| "Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size" }); |
| } catch (Exception exception){ |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, exception); |
| } |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Answer the fully qualified names of the classes mapped in the session. |
| * This uses the mappedClass from the CMPPolicy. |
| * |
| * @return java.util.Vector |
| */ |
| private Vector<String> getMappedClassNames() { |
| Map<String, Boolean> alreadyAdded = new HashMap<>(); |
| Vector<String> mappedClassNames = new Vector<>(); |
| String mappedClassName = null; |
| |
| Iterator<ClassDescriptor> descriptorsIterator = getSession().getProject().getDescriptors() |
| .values().iterator(); |
| while (descriptorsIterator.hasNext()) { |
| ClassDescriptor nextDescriptor = descriptorsIterator.next(); |
| |
| // differentiate between a generated class and not, by comparing the descriptor's Java class |
| if (nextDescriptor.getCMPPolicy() != null) { |
| if (nextDescriptor.getCMPPolicy().getMappedClass() != null) { |
| mappedClassName = nextDescriptor.getCMPPolicy().getMappedClass().getName(); |
| } |
| } |
| |
| if (mappedClassName == null) { |
| mappedClassName = nextDescriptor.getJavaClassName(); |
| } |
| if (alreadyAdded.get(mappedClassName) == null) { |
| alreadyAdded.put(mappedClassName, Boolean.TRUE); |
| mappedClassNames.addElement(mappedClassName); |
| } |
| mappedClassName = null; |
| } |
| return mappedClassNames; |
| } |
| |
| /** |
| * INTERNAL: |
| * This method traverses the EclipseLink descriptors and returns a Vector of the descriptor's |
| * reference class names that match the provided filter. The filter is a comma separated |
| * list of strings to match against. |
| * |
| * @param filter A comma separated list of strings to match against. |
| * @return A Vector of class names that match the filter. |
| */ |
| public Vector<String> getMappedClassNamesUsingFilter(String filter) { |
| //Output Vector |
| Vector<String> outputVector = new Vector<>(); |
| |
| //Input mapped class names |
| Vector<String> mappedClassNames = getMappedClassNames(); |
| |
| //Input filter values |
| List<String> filters = new ArrayList<>(); |
| StringTokenizer lineTokens = new StringTokenizer(filter, ","); |
| while (lineTokens.hasMoreTokens()) { |
| filters.add(lineTokens.nextToken()); |
| } |
| for (int i = 0; i < mappedClassNames.size(); i++) { |
| String className = mappedClassNames.get(i); |
| String classNameLowerCase = mappedClassNames.get(i).toLowerCase(); |
| for (int j = 0; j < filters.size(); j++) { |
| String filterValue = (Helper.rightTrimString(filters.get(j)).trim()).toLowerCase(); |
| if (filterValue.indexOf('*') == 0) { |
| filterValue = filterValue.substring(1); |
| } |
| try { |
| //Note: String.matches(String regex) since jdk1.4 |
| if (classNameLowerCase.matches(new StringBuilder().append("^.*").append(filterValue).append(".*$").toString())) { |
| if (!outputVector.contains(className)) { |
| outputVector.add(className); |
| } |
| } |
| } catch (PatternSyntaxException exception) { |
| //regular expression syntax error |
| AbstractSessionLog.getLog().log(SessionLog.FINEST, "pattern_syntax_error", exception); |
| } |
| } |
| } |
| Collections.sort(outputVector); |
| return outputVector; |
| } |
| |
| |
| |
| /** |
| * INTERNAL: |
| * getCacheTypeFor: Give a more UI-friendly version of the cache type |
| */ |
| protected String getCacheTypeFor(Class identityMapClass) { |
| if (identityMapClass == CacheIdentityMap.class) { |
| return "Cache"; |
| } else if (identityMapClass == FullIdentityMap.class) { |
| return "Full"; |
| } else if (identityMapClass == HardCacheWeakIdentityMap.class) { |
| return "HardWeak"; |
| } else if (identityMapClass == NoIdentityMap.class) { |
| return "None"; |
| } else if (identityMapClass == SoftCacheWeakIdentityMap.class) { |
| return "SoftWeak"; |
| } else if (identityMapClass == WeakIdentityMap.class) { |
| return "Weak"; |
| } else if (identityMapClass == SoftIdentityMap.class) { |
| return "Soft"; |
| } |
| return "N/A"; |
| } |
| |
| /** |
| * getModuleName(): Answer the name of the context-root of the application that this session is associated with. |
| * Answer "unknown" if there is no module name available. |
| * Default behavior is to return "unknown" - we override this behavior here for WebLogic. |
| */ |
| public String getModuleName() { |
| return getSession() |
| .getServerPlatform().getModuleName(); |
| } |
| |
| |
| /** |
| * getApplicationName(): Answer the name of the module (EAR name) that this session is associated with. |
| * Answer "unknown" if there is no application name available. |
| * Default behavior is to return "unknown" - we override this behavior here for all platform implementors of JMXEnabledPlatform |
| */ |
| public String getApplicationName() { |
| return ((JMXEnabledPlatform) getSession() |
| .getServerPlatform()).getApplicationName(); |
| } |
| |
| /** |
| * Method returns if all Parameters should be bound or not |
| */ |
| public Boolean getShouldBindAllParameters() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return Boolean.FALSE; |
| } |
| return ((DatabaseLogin) getSession().getDatasourceLogin()).shouldBindAllParameters(); |
| } |
| |
| /** |
| * Return the size of strings after which will be bound into the statement |
| * If we are not using a DatabaseLogin, or we're not using string binding, |
| * answer 0 (zero). |
| */ |
| public Integer getStringBindingSize() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return 0; |
| } |
| if (!getSession().getDatasourceLogin().getPlatform().usesStringBinding()) { |
| return 0; |
| } |
| return ((DatabaseLogin) getSession().getDatasourceLogin()).getStringBindingSize(); |
| } |
| |
| /** |
| * This method will return if batchWriting is in use or not. |
| */ |
| public Boolean getUsesBatchWriting() { |
| return getSession().getDatasourceLogin().getPlatform().usesBatchWriting(); |
| } |
| |
| /** |
| * This method will return a long indicating the exact time in Milliseconds that the |
| * session connected to the database. |
| */ |
| public Long getTimeConnectionEstablished() { |
| return ((DatabaseSessionImpl) getSession()).getConnectedTime(); |
| } |
| |
| /** |
| * This method will return if batchWriting is in use or not. |
| */ |
| public Boolean getUsesJDBCBatchWriting() { |
| if (!(getSession().getDatasourceLogin().getDatasourcePlatform() instanceof DatabasePlatform)) { |
| return Boolean.FALSE; |
| } |
| return getSession().getDatasourceLogin().getPlatform().usesJDBCBatchWriting(); |
| } |
| |
| /** |
| * Shows if Byte Array Binding is turned on or not |
| */ |
| public Boolean getUsesByteArrayBinding() { |
| if (!(getSession().getDatasourceLogin().getDatasourcePlatform() instanceof DatabasePlatform)) { |
| return Boolean.FALSE; |
| } |
| return getSession().getDatasourceLogin().getPlatform().usesByteArrayBinding(); |
| } |
| |
| /** |
| * Shows if native SQL is being used |
| */ |
| public Boolean getUsesNativeSQL() { |
| if (!(getSession().getDatasourceLogin().getDatasourcePlatform() instanceof DatabasePlatform)) { |
| return Boolean.FALSE; |
| } |
| return getSession().getDatasourceLogin().getPlatform().usesNativeSQL(); |
| } |
| |
| /** |
| * This method indicates if streams are being used for binding |
| */ |
| public Boolean getUsesStreamsForBinding() { |
| if (!(getSession().getDatasourceLogin().getDatasourcePlatform() instanceof DatabasePlatform)) { |
| return Boolean.FALSE; |
| } |
| return getSession().getDatasourceLogin().getPlatform().usesStreamsForBinding(); |
| } |
| |
| /** |
| * This method indicates if Strings are being bound |
| */ |
| public Boolean getUsesStringBinding() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return Boolean.FALSE; |
| } |
| return getSession().getDatasourceLogin().getPlatform().usesStringBinding(); |
| } |
| |
| /** |
| * Returns if statements should be cached or not |
| */ |
| public boolean getShouldCacheAllStatements() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return Boolean.FALSE; |
| } |
| return ((DatabaseLogin) getSession().getDatasourceLogin()).shouldCacheAllStatements(); |
| } |
| |
| /** |
| * Used to clear the statement cache. Only valid if statements are being cached |
| */ |
| public synchronized void clearStatementCache() { |
| if (!(getSession().getDatasourceLogin() instanceof DatabaseLogin)) { |
| return; |
| } |
| ((DatabaseAccessor)getSession().getAccessor()).clearStatementCache(getSession()); |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_statement_cache_cleared"); |
| |
| } |
| |
| /** |
| * This method will print the available Connection pools to the SessionLog. |
| */ |
| public void printAvailableConnectionPools() { |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| Map<String, ConnectionPool> pools = ((ServerSession)getSession()).getConnectionPools(); |
| Iterator<String> poolNames = pools.keySet().iterator(); |
| while (poolNames.hasNext()) { |
| String poolName = poolNames.next().toString(); |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_pool_name", poolName); |
| } |
| } else { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_no_connection_pools_available"); |
| |
| } |
| } |
| |
| /** |
| * This method will retrieve the max size of a particular connection pool |
| * @param poolName the name of the pool to get the max size for |
| * @return Integer for the max size of the pool. Return -1 if pool doesn't exist. |
| */ |
| public Integer getMaxSizeForPool(String poolName) { |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| ConnectionPool connectionPool = ((ServerSession)getSession()).getConnectionPool(poolName); |
| if (connectionPool != null) { |
| return connectionPool.getMaxNumberOfConnections(); |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * This method will retrieve the min size of a particular connection pool |
| * @param poolName the name of the pool to get the min size for |
| * @return Integer for the min size of the pool. Return -1 if pool doesn't exist. |
| */ |
| public Integer getMinSizeForPool(String poolName) { |
| if (ClassConstants.ServerSession_Class.isAssignableFrom(getSession().getClass())) { |
| ConnectionPool connectionPool = ((ServerSession)getSession()).getConnectionPool(poolName); |
| if (connectionPool != null) { |
| return connectionPool.getMinNumberOfConnections(); |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * This method is used to output those Class Names that have identity Maps in the Session. |
| * Please note that SubClasses and aggregates will be missing from this list as they do not have |
| * separate identity maps. |
| */ |
| public void printClassesInSession() { |
| Vector classes = getSession().getIdentityMapAccessorInstance().getIdentityMapManager().getClassesRegistered(); |
| int index; |
| if (classes.isEmpty()) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_no_classes_in_session"); |
| return; |
| } |
| |
| for (index = 0; index < classes.size(); index++) { |
| getSession().getSessionLog().log(SessionLog.FINEST, (String)classes.elementAt(index)); |
| } |
| } |
| |
| /** |
| * This method will log the objects in the Identity Map. |
| * There is no particular order to these objects. |
| * @param className the fully qualified classname identifying the identity map |
| * @exception ClassNotFoundException thrown then the IdentityMap for that class name could not be found |
| */ |
| public void printObjectsInIdentityMap(String className) throws ClassNotFoundException { |
| Class classWithMap = getSession().getDatasourcePlatform().getConversionManager().convertObject(className, ClassConstants.CLASS); |
| IdentityMap map = getSession().getIdentityMapAccessorInstance().getIdentityMap(classWithMap); |
| |
| //check if the identity map exists |
| if (null == map) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_identity_map_non_existent", className); |
| return; |
| } |
| |
| //check if there are any objects in the identity map. Print if so. |
| Enumeration<CacheKey> objects = map.keys(); |
| if (!objects.hasMoreElements()) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_identity_map_empty", className); |
| } |
| |
| CacheKey cacheKey; |
| while (objects.hasMoreElements()) { |
| cacheKey = objects.nextElement(); |
| if(null != cacheKey && null != cacheKey.getKey() && null != cacheKey.getObject()) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_print_cache_key_value", |
| cacheKey.getKey().toString(), cacheKey.getObject().toString()); |
| } |
| } |
| } |
| |
| /** |
| * This method will log the types of Identity Maps in the session. |
| */ |
| public void printAllIdentityMapTypes() { |
| Vector classesRegistered = getSession().getIdentityMapAccessorInstance().getIdentityMapManager().getClassesRegistered(); |
| String registeredClassName; |
| Class registeredClass; |
| |
| //Check if there aren't any classes registered |
| if (classesRegistered.size() == 0) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_no_identity_maps_in_session"); |
| return; |
| } |
| |
| //get each identity map, and log the type |
| for (int index = 0; index < classesRegistered.size(); index++) { |
| registeredClassName = (String)classesRegistered.elementAt(index); |
| registeredClass = getSession().getDatasourcePlatform().getConversionManager().convertObject(registeredClassName, ClassConstants.CLASS); |
| IdentityMap map = getSession().getIdentityMapAccessorInstance().getIdentityMap(registeredClass); |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_identity_map_class", |
| registeredClassName, map.getClass()); |
| } |
| } |
| |
| /** |
| * This method will log all objects in all Identity Maps in the session. |
| */ |
| public void printObjectsInIdentityMaps() { |
| Vector classesRegistered = getSession().getIdentityMapAccessorInstance().getIdentityMapManager().getClassesRegistered(); |
| String registeredClassName; |
| |
| //Check if there aren't any classes registered |
| if (classesRegistered.size() == 0) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_no_identity_maps_in_session"); |
| return; |
| } |
| |
| //get each identity map, and log the type |
| for (int index = 0; index < classesRegistered.size(); index++) { |
| registeredClassName = (String)classesRegistered.elementAt(index); |
| try { |
| this.printObjectsInIdentityMap(registeredClassName); |
| } catch (ClassNotFoundException classNotFound) { |
| //we are enumerating registered classes, so this shouldn't happen. Print anyway |
| classNotFound.printStackTrace(); |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, classNotFound); |
| } |
| } |
| } |
| |
| /** |
| * This method will SUM and return the number of objects in all Identity Maps in the session. |
| */ |
| public Integer getNumberOfObjectsInAllIdentityMaps() { |
| Vector classesRegistered = getSession().getIdentityMapAccessorInstance().getIdentityMapManager().getClassesRegistered(); |
| String registeredClassName; |
| int sum = 0; |
| |
| //Check if there aren't any classes registered |
| if (classesRegistered.size() == 0) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_no_identity_maps_in_session"); |
| return 0; |
| } |
| |
| //get each identity map, and log the size |
| for (int index = 0; index < classesRegistered.size(); index++) { |
| registeredClassName = (String)classesRegistered.elementAt(index); |
| try { |
| sum += this.getNumberOfObjectsInIdentityMap(registeredClassName); |
| } catch (ClassNotFoundException classNotFound) { |
| //we are enumerating registered classes, so this shouldn't happen. Print anyway |
| classNotFound.printStackTrace(); |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, classNotFound); |
| } |
| } |
| |
| return sum; |
| } |
| |
| /** |
| * This method will answer the number of persistent classes contained in the session. |
| * This does not include aggregates. |
| */ |
| public Integer getNumberOfPersistentClasses() { |
| Map classesTable = new HashMap(); |
| ClassDescriptor currentDescriptor; |
| |
| //use a table to eliminate duplicate classes. Ignore Aggregates |
| Iterator<ClassDescriptor> descriptors = getSession().getProject().getDescriptors().values().iterator(); |
| while (descriptors.hasNext()) { |
| currentDescriptor = descriptors.next(); |
| if (!currentDescriptor.isAggregateDescriptor()) { |
| classesTable.put(currentDescriptor.getJavaClassName(), Boolean.TRUE); |
| } |
| } |
| |
| return classesTable.size(); |
| } |
| |
| /** |
| * Return the log type, either "EclipseLink", "Java" or the simple name of the logging class used. |
| * |
| * @return the log type |
| */ |
| public String getLogType() { |
| if (this.getSession().getSessionLog().getClass() == JavaLog.class) { |
| return "Java"; |
| } else if (this.getSession().getSessionLog().getClass() == DefaultSessionLog.class) { |
| return EclipseLink_Product_Name; |
| } else { |
| return this.getSession().getSessionLog().getClass().getSimpleName(); |
| } |
| } |
| |
| /** |
| * Return the database platform used by the DatabaseSession. |
| * |
| * @return String databasePlatform |
| */ |
| public String getDatabasePlatform() { |
| return getSession().getDatasourcePlatform().getClass().getName(); |
| } |
| |
| /** |
| * Return JDBCConnection detail information. This includes URL and datasource information. |
| */ |
| public synchronized String getJdbcConnectionDetails() { |
| return getSession().getLogin().getConnector().getConnectionDetails(); |
| } |
| |
| /** |
| * Return connection pool type. Values include: "Internal", "External" and "N/A". |
| */ |
| public synchronized String getConnectionPoolType() { |
| if (getSession().getLogin().shouldUseExternalConnectionPooling()) { |
| return "External"; |
| } else { |
| return "N/A"; |
| } |
| } |
| |
| /** |
| * Return db driver class name. This only applies to DefaultConnector. Return "N/A" otherwise. |
| */ |
| public synchronized String getDriver() { |
| if (getSession().getLogin().getConnector() instanceof DefaultConnector) { |
| return getSession().getLogin().getDriverClassName(); |
| } |
| return "N/A"; |
| } |
| |
| /** |
| * Return the log filename. This returns the fully qualified path of the log file when |
| * EclipseLink DefaultSessionLog instance is used. Null is returned otherwise. |
| * |
| * @return String logFilename |
| */ |
| public String getLogFilename() { |
| // returns String or null. |
| if ( session.getSessionLog() instanceof DefaultSessionLog) { |
| return ((DefaultSessionLog)session.getSessionLog()).getWriterFilename(); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * This method is used to initialize the identity maps in the session. |
| */ |
| public synchronized void initializeAllIdentityMaps() { |
| getSession().getIdentityMapAccessor().initializeAllIdentityMaps(); |
| } |
| |
| /** |
| * This method is used to initialize the identity maps specified by the Vector of classNames. |
| * |
| * @param classNames String[] of fully qualified classnames identifying the identity maps to initialize |
| */ |
| public synchronized void initializeIdentityMaps(String[] classNames) throws ClassNotFoundException { |
| for (int index = 0; index < classNames.length; index++) { |
| initializeIdentityMap(classNames[index]); |
| } |
| } |
| |
| /** |
| * This method is used to invalidate the identity maps in the session. |
| */ |
| public synchronized void invalidateAllIdentityMaps() { |
| Vector classesRegistered = getSession().getIdentityMapAccessorInstance().getIdentityMapManager().getClassesRegistered(); |
| String registeredClassName; |
| Class registeredClass; |
| |
| if (classesRegistered.isEmpty()) { |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_no_identity_maps_in_session"); |
| } |
| |
| //get each identity map, and invalidate |
| for (int index = 0; index < classesRegistered.size(); index++) { |
| registeredClassName = (String)classesRegistered.elementAt(index); |
| registeredClass = getSession().getDatasourcePlatform().getConversionManager() |
| .convertObject(registeredClassName, ClassConstants.CLASS); |
| getSession().getIdentityMapAccessor().invalidateClass(registeredClass); |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_identity_map_invalidated", registeredClassName); |
| } |
| } |
| |
| /** |
| * This method is used to invalidate the identity maps specified by the String[] of classNames. |
| * |
| * @param classNamesParam String[] of fully qualified classnames identifying the identity maps to invalidate |
| * @param recurse Boolean indicating if we want to invalidate the children identity maps too |
| */ |
| public synchronized void invalidateIdentityMaps(String[] classNamesParam, Boolean recurse) throws ClassNotFoundException { |
| String[] classNames = classNamesParam; |
| for (int index = 0; index < classNames.length; index++) { |
| invalidateIdentityMap(classNames[index], recurse); |
| } |
| } |
| |
| /** |
| * This method is used to invalidate the identity maps specified by className. This does not |
| * invalidate the children identity maps |
| * |
| * @param className the fully qualified classname identifying the identity map to invalidate |
| */ |
| public synchronized void invalidateIdentityMap(String className) throws ClassNotFoundException { |
| this.invalidateIdentityMap(className, Boolean.FALSE); |
| } |
| |
| /** |
| * This method is used to invalidate the identity maps specified by className. |
| * |
| * @param className the fully qualified classname identifying the identity map to invalidate |
| * @param recurse Boolean indicating if we want to invalidate the children identity maps too |
| */ |
| public synchronized void invalidateIdentityMap(String className, Boolean recurse) throws ClassNotFoundException { |
| Class registeredClass; |
| |
| //get identity map, and invalidate |
| registeredClass = getSession().getDatasourcePlatform().getConversionManager() |
| .convertObject(className, ClassConstants.CLASS); |
| getSession().getIdentityMapAccessor().invalidateClass(registeredClass); |
| ((AbstractSession)session).log(SessionLog.INFO, SessionLog.SERVER, "jmx_mbean_runtime_services_identity_map_invalidated", className); |
| } |
| |
| /** |
| * |
| * INTERNAL: |
| * Convert the TabularData to a two-dimensional array |
| * @param tdata the TabularData to be converted |
| * @param names the order of the columns |
| * @return a two-dimensional array |
| */ |
| private Object[][] tabularDataTo2DArray(TabularData tdata, String[] names) throws Exception { |
| if(tdata==null){ |
| return null; |
| } |
| Object[] rows = tdata.values().toArray(); |
| Object[][] data = new Object[rows.length][]; |
| |
| for (int i = 0; i < rows.length; i++) { |
| CompositeData cdata = ((CompositeData) rows[i]); |
| Object[] returnRow = new Object[names.length]; |
| for (int j = 0; j < names.length; j++) { |
| String name = names[j]; |
| Object value = cdata.get(name); |
| returnRow[j] = name + " : " + String.valueOf(value); |
| } |
| data[i] = returnRow; |
| } |
| return data; |
| } |
| |
| /** |
| * INTERNAL: |
| * Define the session that this instance is providing runtime services for |
| * |
| * @param newSession The session to be used with these RuntimeServices |
| */ |
| protected void setSession(AbstractSession newSession) { |
| this.session = newSession; |
| this.updateDeploymentTimeData(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Answer the CompositeType describing the CompositeData that we return for |
| * each IdentityMap (or subclass). |
| * |
| * This is mostly for the client side to see what kind of information is returned. |
| * @return javax.management.openmbean.CompositeType |
| */ |
| private CompositeType buildCompositeTypeForClassSummaryDetails() throws OpenDataException { |
| return new CompositeType("Class Details", "Details of class for Class Summary", new String[] { |
| "Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size" }, new String[] { |
| "Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size" }, new OpenType[] { |
| SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING }); |
| } |
| |
| |
| /** |
| * Provide a list of instance of ClassSummaryDetail containing information about the |
| * classes in the session whose class names match the provided filter. |
| * |
| * ClassSummaryDetail is a model specific class that can be used internally by the Portable JMX Framework to |
| * convert class attribute to JMX required open type, it has:- |
| * 1. model specific type that needs to be converted : ["Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size"] |
| * 2. convert methods. |
| * |
| * @param filter A comma separated list of strings to match against. |
| * @return A ArrayList of instance of ClassSummaryDetail containing class information for the class names that match the filter. |
| */ |
| public List<ClassSummaryDetailBase> getClassSummaryDetailsUsingFilterArray(String filter) { |
| try { |
| // if the filter is null, return all the details |
| Vector<String> mappedClassNames = getMappedClassNamesUsingFilter(filter); |
| String mappedClassName; |
| List<ClassSummaryDetailBase> classSummaryDetails = new ArrayList<>(); |
| // Check if there aren't any classes mapped |
| if (mappedClassNames.size() == 0) { |
| return null; |
| } |
| CompositeType type = buildCompositeTypeForClassSummaryDetails(); |
| // get details for each class, and add the details to the summary |
| for (int index = 0; index < mappedClassNames.size(); index++) { |
| mappedClassName = mappedClassNames.elementAt(index); |
| Map<String, String> data = buildLowlevelDetailsFor(mappedClassName); |
| final CompositeDataSupport support = new CompositeDataSupport(type, buildLowlevelDetailsFor(mappedClassName)); |
| classSummaryDetails.add(ClassSummaryDetailBase.from(support)); |
| } |
| return classSummaryDetails; |
| } catch (Exception openTypeException) { |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, openTypeException); |
| openTypeException.printStackTrace(); |
| } |
| |
| // wait to get requirements from EM |
| return null; |
| } |
| |
| /** |
| * Provide a list of instance of ClassSummaryDetail containing information about all |
| * classes in the session. |
| * |
| * ClassSummaryDetail is a model specific class that can be used internally by the Portable JMX Framework to |
| * convert class attribute to JMX required open type, it has:- |
| * 1. model specific type that needs to be converted : ["Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size"] |
| * 2. convert methods. |
| * |
| * @return A List of instance of ClassSummaryDetail objects containing class information for the class names that match the filter. |
| */ |
| public List<ClassSummaryDetailBase> getClassSummaryDetailsArray() { |
| // wait to get requirements from EM |
| return getClassSummaryDetailsUsingFilterArray(".*"); |
| } |
| |
| /** |
| * INTERNAL: |
| * Answer the TabularType describing the TabularData that we return from |
| * getCacheSummaryDetails() and getCacheSummaryDetails(String filter) |
| * |
| * This is mostly for the client side to see what kind of information is returned. |
| * |
| * @return javax.management.openmbean.TabularType |
| */ |
| private TabularType buildTabularTypeForClassSummaryDetails() throws OpenDataException { |
| return new TabularType(getSessionName(), "Session description", buildCompositeTypeForClassSummaryDetails(), |
| new String[] { "Class Name" }); |
| } |
| |
| |
| /** |
| * INTERNAL: |
| * Answer the CompositeData containing the cache details for the given mappedClassName |
| * This uses a CompositeDataSupport, which implements CompositeData |
| * |
| * @param mappedClassName fullyQualified class name of the class |
| * @param detailsType describes the format of the returned CompositeData |
| |
| * @return javax.management.openmbean.CompositeData |
| */ |
| private CompositeData buildDetailsFor(String mappedClassName, CompositeType detailsType) throws Exception { |
| return new CompositeDataSupport(detailsType, buildLowlevelDetailsFor(mappedClassName)); |
| } |
| |
| /** |
| * INTERNAL: |
| * Helper to build a HashMap to help in the construction of a CompositeData |
| * |
| * @param mappedClassName fullyQualified class name of the class |
| |
| * @return HashMap |
| */ |
| private Map<String, String> buildLowlevelDetailsFor(String mappedClassName) { |
| Class mappedClass = getSession().getDatasourcePlatform().getConversionManager().convertObject(mappedClassName, ClassConstants.CLASS); |
| ClassDescriptor descriptor = getSession().getProject().getDescriptor(mappedClass); |
| |
| String cacheType = ""; |
| String configuredSize = ""; |
| String currentSize = ""; |
| String parentClassName = ""; |
| |
| // Aggregate descriptors do not have an IdentityMap |
| if (!descriptor.isAggregateDescriptor()) { |
| IdentityMap identityMap = getSession().getIdentityMapAccessorInstance().getIdentityMap(descriptor); |
| cacheType = getCacheTypeFor(identityMap.getClass()); |
| configuredSize = String.valueOf(identityMap.getMaxSize()); |
| //show the current size, including subclasses |
| currentSize = String.valueOf(identityMap.getSize(mappedClass, true)); |
| } |
| |
| //If I have a parent class name, get it. Otherwise, leave blank |
| if (descriptor.hasInheritance()) { |
| if (descriptor.getInheritancePolicy().getParentDescriptor() != null) { |
| parentClassName = descriptor.getInheritancePolicy().getParentClassName(); |
| } |
| } |
| |
| boolean isChildDescriptor = descriptor.isChildDescriptor(); |
| |
| Map<String, String> details = new HashMap<>(5); |
| details.put("Class Name", mappedClassName); |
| details.put("Cache Type", (isChildDescriptor ? "" : cacheType)); |
| details.put("Configured Size", (isChildDescriptor ? "" : configuredSize)); |
| details.put("Current Size", currentSize); |
| details.put("Parent Class Name", parentClassName); |
| |
| return details; |
| } |
| |
| |
| /** |
| * INTERNAL: |
| * Provide an instance of TabularData containing information about the |
| * classes in the session whose class names match the provided filter. |
| * |
| * The TabularData contains rowData with values being CompositeData(s) |
| * |
| * CompositeData has: |
| * CompositeType: column names are ["Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size"] |
| * |
| * Each CompositeData can have get(myColumnName) sent to it. |
| * |
| * |
| * @param filter A comma separated list of strings to match against. |
| * @return A TabularData of information for the class names that match the filter. |
| */ |
| private TabularData buildClassSummaryDetailsUsingFilter(String filter) { |
| // if the filter is null, return all the details |
| if (filter == null) { |
| return buildClassSummaryDetails(); |
| } |
| |
| try { |
| Vector<String> mappedClassNames = getMappedClassNamesUsingFilter(filter); |
| String mappedClassName; |
| TabularDataSupport rowData = new TabularDataSupport(buildTabularTypeForClassSummaryDetails()); |
| // Check if there aren't any classes mapped |
| if (mappedClassNames.size() == 0) { |
| return null; |
| } |
| |
| // get details for each class, and add the details to the summary |
| for (int index = 0; index < mappedClassNames.size(); index++) { |
| mappedClassName = mappedClassNames.elementAt(index); |
| String[] key = new String[] { mappedClassName }; |
| rowData.put(key, buildDetailsFor(mappedClassName, rowData.getTabularType().getRowType())); |
| } |
| return rowData; |
| } catch (Exception exception) { |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, exception); |
| } |
| |
| // wait to get requirements from EM |
| return null; |
| } |
| |
| /** |
| * INTERNAL: |
| * Provide an instance of TabularData containing information about all |
| * classes in the session. |
| * |
| * The TabularData contains rowData with values being CompositeData(s) |
| * |
| * CompositeData has: |
| * CompositeType: column names are ["Class Name", "Parent Class Name", "Cache Type", "Configured Size", "Current Size"] |
| * |
| * Each CompositeData can have get(myColumnName) sent to it. |
| * |
| */ |
| private TabularData buildClassSummaryDetails() { |
| try { |
| Vector<String> mappedClassNames = getMappedClassNames(); |
| String mappedClassName; |
| TabularDataSupport rowData = new TabularDataSupport(buildTabularTypeForClassSummaryDetails()); |
| // Check if there aren't any classes mapped |
| if (mappedClassNames.size() == 0) { |
| return null; |
| } |
| |
| // get details for each class, and add the details to the summary |
| for (int index = 0; index < mappedClassNames.size(); index++) { |
| mappedClassName = mappedClassNames.elementAt(index); |
| String[] key = new String[] { mappedClassName }; |
| rowData.put(key, buildDetailsFor(mappedClassName, rowData.getTabularType().getRowType())); |
| } |
| |
| return rowData; |
| } catch (Exception exception) { |
| AbstractSessionLog.getLog().log(SessionLog.SEVERE, "jmx_enabled_platform_mbean_runtime_exception", PLATFORM_NAME, exception); |
| } |
| |
| // wait to get requirements from EM |
| return null; |
| } |
| } |