|
Glassfish example source code file (LoggingImpl.java)
This example Glassfish source code file (LoggingImpl.java) is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.
The Glassfish LoggingImpl.java source code
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 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.
*/
package org.glassfish.admin.amx.impl.ext;
import org.glassfish.external.amx.AMXGlassfish;
import org.glassfish.admin.amx.core.Util;
import org.glassfish.admin.amx.logging.Logging;
import org.glassfish.admin.amx.logging.LogQueryResult;
import static org.glassfish.admin.amx.logging.Logging.*;
import com.sun.common.util.logging.LoggingConfigImpl;
import org.glassfish.admin.amx.util.jmx.JMXUtil;
import org.glassfish.admin.amx.util.jmx.NotificationBuilder;
import org.glassfish.admin.amx.util.*;
import com.sun.enterprise.server.logging.GFFileHandler;
import com.sun.enterprise.server.logging.logviewer.backend.LogFilter;
import com.sun.enterprise.server.logging.diagnostics.MessageIdCatalog;
//import com.sun.enterprise.server.logging.ModuleToLoggerNameMapper;
import org.glassfish.admin.amx.impl.util.InjectedValues;
import org.glassfish.server.ServerEnvironmentImpl;
import org.glassfish.admin.amx.util.CollectionUtil;
import javax.management.*;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import org.glassfish.admin.amx.impl.mbean.AMXImplBase;
import static org.glassfish.admin.amx.logging.LogRecordEmitter.*;
import static org.glassfish.admin.amx.logging.LogFileAccess.*;
import static org.glassfish.admin.amx.logging.LogAnalyzer.*;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.component.Habitat;
//import com.sun.enterprise.server.logging.LoggingImplHook;
/**
Implementation of {@link Logging}.
<p>
The following is a GlassFish V2 comment, and needs work for v3:<br>
AMX Logging MBean is hooked directly into the logging subsystem
via com.sun.enterprise.server.logging.FileandSyslogHandler which uses
com.sun.enterprise.server.logging.AMXLoggingHook to instantiate
and call an instance of LoggingImpl.
*/
@Service
public final class LoggingImpl extends AMXImplBase
//implements /*Logging,*/ LoggingImplHook
{
private final Map<Level,String> mLevelToNotificationTypeMap;
private final Map<String,NotificationBuilder> mNotificationTypeToNotificationBuilderMap;
private static final String SERVER_LOG_NAME = "server.log";
private static final String ACCESS_LOG_NAME = "access.log";
private final LoggingConfigImpl loggingConfig;
private final GFFileHandler gfFileHandler;
private final LogFilter logFilter;
private final MessageIdCatalog msgIdCatalog;
private final Logger logger;
private final Habitat mHabitat;
final String FILE_SEP;
private final String mServerName;
/**
Used internally to get the Logging ObjectName for a particular server
Logging MBean is a special-case because it needs to load as early
as possible.
*/
public static ObjectName
getObjectName( final String serverName )
{
final String requiredProps = Util.makeRequiredProps( Util.deduceType(Logging.class), serverName );
final String ServerRootMonitorType = "ServerRootMonitor";
final String parentProp = Util.makeProp( ServerRootMonitorType, serverName );
final String props = Util.concatenateProps( requiredProps, parentProp );
return Util.newObjectName( AMXGlassfish.DEFAULT.amxJMXDomain(), props );
}
/**
*/
public LoggingImpl( final ObjectName parent, final String serverName)
{
super( parent, Logging.class );
mServerName = serverName;
FILE_SEP = System.getProperty( "file.separator" );
mLevelToNotificationTypeMap = initLevelToNotificationTypeMap();
mNotificationTypeToNotificationBuilderMap = new HashMap<String,NotificationBuilder>();
final ServerEnvironmentImpl env = InjectedValues.getInstance().getServerEnvironment();
loggingConfig = new LoggingConfigImpl();
loggingConfig.setupConfigDir(env.getConfigDirPath(), env.getLibPath());
msgIdCatalog = new MessageIdCatalog();
mHabitat = InjectedValues.getInstance().getHabitat();
gfFileHandler = mHabitat.getComponent(GFFileHandler.class);
logFilter = mHabitat.getComponent(LogFilter.class);
logger = Logger.getAnonymousLogger();
}
/**
Hook for subclass to modify anything in MBeanInfo.
@Override
*/
/*
@Override
protected MBeanInfo
postRegisterModifyMBeanInfo( final MBeanInfo info )
{
final MBeanOperationInfo[] ops = info.getOperations();
final int idx = JMXUtil.findMBeanOperationInfo( info, "queryServerLog", null);
final MBeanOperationInfo op = ops[idx];
ops[idx] = new MBeanOperationInfo( op.getName(), op.getDescription(),
op.getSignature(), Map.class.getName(),
MBeanOperationInfo.INFO );
return JMXUtil.newMBeanInfo( info, ops );
}
*/
private static MBeanNotificationInfo[] SELF_NOTIFICATION_INFOS = null;
/**
getMBeanInfo() can be called frequently. By making this static,
we avoid needlessly creating new Objects.
*/
private static synchronized MBeanNotificationInfo[]
getSelfNotificationInfos()
{
if ( SELF_NOTIFICATION_INFOS == null )
{
final String[] types = SetUtil.toStringArray( ALL_LOG_RECORD_NOTIFICATION_TYPES );
final MBeanNotificationInfo selfInfo = new MBeanNotificationInfo(
types, Notification.class.getName(), "LogRecord notifications" );
SELF_NOTIFICATION_INFOS = new MBeanNotificationInfo[] { selfInfo };
}
return( SELF_NOTIFICATION_INFOS );
}
public MBeanNotificationInfo[]
getNotificationInfo()
{
final MBeanNotificationInfo[] superInfos = super.getNotificationInfo();
final MBeanNotificationInfo[] all =
JMXUtil.mergeMBeanNotificationInfos( superInfos, getSelfNotificationInfos() );
return all;
}
/** FIXME */
private void unimplemented()
{
throw new RuntimeException( "Not implemented.");
}
public void
setModuleLogLevel(
final String module,
final String level )
{
try {
loggingConfig.setLoggingProperty( module+".level", level );
} catch (java.io.IOException e) {
logger.log (Level.SEVERE, "Can not set module log level");
}
}
public String
getModuleLogLevel( final String module)
{
try {
Map<String, String> props = loggingConfig.getLoggingProperties();
if (props != null)
return props.get(module+".level");
return null;
} catch (java.io.IOException e){
logger.log (Level.SEVERE, "Can not get module log level");
return null;
}
}
public Map<String,String>
getLoggingProperties( )
{
try {
Map<String, String> props = loggingConfig.getLoggingProperties();
return props;
} catch (java.io.IOException e){
logger.log (Level.WARNING, "Can not get module log level");
return null;
}
}
public void
updateLoggingProperties(final Map<String, String> properties)
{
try {
loggingConfig.updateLoggingProperties(properties);
} catch (java.io.IOException e){
logger.log (Level.WARNING, "Can not get module log level");
}
}
public int
getLogLevelListenerCount( final Level logLevel )
{
final String notifType = logLevelToNotificationType( logLevel );
final int count = getNotificationEmitter().getNotificationTypeListenerCount( notifType );
return( count );
}
public String[]
getLogFileKeys()
{
unimplemented();
return new String[] { SERVER_KEY, ACCESS_KEY };
}
public synchronized String[]
getLogFileNames( final String key )
{
String[] result = null;
if ( SERVER_KEY.equals( key ) )
{
}
else
{
throw new IllegalArgumentException( key );
}
return result;
}
public Map <String, String> getLoggingAttributes( )
{
String gfHandler = "com.sun.enterprise.server.logging.GFFileHandler";
String sysHandler = "com.sun.enterprise.server.logging.SyslogHandler";
try {
Map<String, String> props = loggingConfig.getLoggingProperties();
if ( props == null)
return null;
Map<String,String> attributes = new HashMap();
attributes.put(gfHandler+".file", props.get(gfHandler+".file"));
attributes.put(gfHandler+".rotationTimelimitInMinutes", props.get(gfHandler+".rotationTimelimitInMinutes"));
attributes.put(gfHandler+".rotationLimitInBytes", props.get(gfHandler+".rotationLimitInBytes"));
attributes.put(gfHandler+".logtoConsole", props.get(gfHandler+".logtoConsole"));
attributes.put(gfHandler+".flushFrequency", props.get(gfHandler+".flushFrequency"));
attributes.put("handlers", props.get("handlers"));
attributes.put(sysHandler+".useSystemLogging", props.get(sysHandler+".useSystemLogging"));
return attributes;
} catch (java.io.IOException e){
logger.log (Level.WARNING, "Can not get logging attributes");
return null;
}
}
public void updateLoggingAttributes( final Map<String,String> properties)
{
try {
loggingConfig.updateLoggingProperties(properties);
} catch (java.io.IOException e){
logger.log (Level.WARNING, "Can not set logging attributes");
}
}
public synchronized void
rotateAllLogFiles()
{
gfFileHandler.rotate( );
}
public synchronized void
rotateLogFile( final String key )
{
if ( ACCESS_KEY.equals( key ) )
{
throw new IllegalArgumentException( "not supported: " + key );
//getLogMBean().rotateAccessLog();
}
else if ( SERVER_KEY.equals( key ) )
{
gfFileHandler.rotate( );
}
else
{
throw new IllegalArgumentException( "" + key );
}
}
private Properties
attributesToProps( List<Attribute> attrs )
{
final Properties props = new Properties();
if ( attrs != null )
{
for( Attribute attr: attrs)
{
final Object value = attr.getValue();
if ( value == null )
{
throw new IllegalArgumentException( attr.getName() + "=" + null);
}
props.put( attr.getName(), value.toString() );
}
}
return( props );
}
private List<Serializable[]>
convertQueryResult( final AttributeList queryResult )
{
// extract field descriptions into a String[]
final AttributeList fieldAttrs = (AttributeList)((Attribute)queryResult.get( 0 )).getValue();
final String[] fieldHeaders = new String[ fieldAttrs.size() ];
for( int i = 0; i < fieldHeaders.length; ++i )
{
final Attribute attr = (Attribute)fieldAttrs.get( i );
fieldHeaders[ i ] = (String)attr.getValue();
}
final List<List srcRecords = TypeCast.asList(
((Attribute)queryResult.get( 1 )).getValue() );
// create the new results, making the first Object[] be the field headers
final List<Serializable[]> results = new ArrayList( srcRecords.size() );
results.add( fieldHeaders );
// extract every record
for( int recordIdx = 0; recordIdx < srcRecords.size(); ++recordIdx )
{
final List<Serializable> record = srcRecords.get( recordIdx );
assert( record.size() == fieldHeaders.length );
final Serializable[] fieldValues = new Serializable[ fieldHeaders.length ];
for( int fieldIdx = 0; fieldIdx < fieldValues.length; ++fieldIdx )
{
fieldValues[ fieldIdx ] = record.get( fieldIdx );
}
results.add( fieldValues );
}
return results;
}
// code in LogBean.java code in v2
public List<Serializable[]>
queryServerLog(
String name,
long startIndex,
boolean searchForward,
int maximumNumberOfResults,
Long fromTime,
Long toTime,
String logLevel,
Set<String> modules,
List<Attribute> nameValuePairs,
String anySearch)
{
final List<Serializable[]> result = queryServerLogInternal(
name, startIndex, searchForward, maximumNumberOfResults,
fromTime, toTime, logLevel, modules, nameValuePairs, anySearch );
return result;
}
private List<Serializable[]>
queryServerLogInternal(
final String name,
final long startIndex,
final boolean searchForward,
final int maximumNumberOfResults,
final Long fromTime,
final Long toTime,
final String logLevel,
final Set<String> modules,
final List<Attribute> nameValuePairs,
final String anySearch)
{
if ( name == null )
{
throw new IllegalArgumentException( "use MOST_RECENT_NAME, not null" );
}
boolean sortAscending = true;
final List<String> moduleList = null;
if (modules != null )
ListUtil.newListFromCollection( modules );
final Properties props = attributesToProps( nameValuePairs );
String actualName;
if ( MOST_RECENT_NAME.equals( name ) )
{
actualName = null;
}
else
{
actualName = name;
}
if (!searchForward)
sortAscending = false;
final AttributeList result= logFilter.getLogRecordsUsingQuery(actualName,
Long.valueOf(startIndex),
searchForward, sortAscending,
maximumNumberOfResults,
fromTime == null ? null
: new Date(fromTime),
toTime == null ? null
: new Date(toTime),
logLevel, false, moduleList, props,anySearch);
return convertQueryResult( result );
}
public Map<String,Number>[]
getErrorInfo()
{
unimplemented();
final List<Map infos = null; //getLogMBean().getErrorInformation();
final Map<String,Number>[] results = TypeCast.asArray( new HashMap[ infos.size() ] );
for( int i = 0; i < results.length; ++i )
{
final Map<String,Object> info = infos.get( i );
assert( info.keySet().size() == 3 );
final Long timestamp = Long.parseLong( info.get( TIMESTAMP_KEY ).toString() );
final Integer severeCount = Integer.parseInt( info.get( SEVERE_COUNT_KEY ).toString() );
final Integer warningCount= Integer.parseInt( info.get( WARNING_COUNT_KEY ).toString() );
final Map<String,Number> item = new HashMap( info.size() );
item.put( TIMESTAMP_KEY, timestamp);
item.put( SEVERE_COUNT_KEY, severeCount);
item.put( WARNING_COUNT_KEY, warningCount);
results[ i ] = item;
}
return results;
}
private static final Integer INTEGER_0 = Integer.valueOf(0);
private static final Map<String,Integer> EMPTY_ERROR_DISTRIBUTION_MAP =
Collections.emptyMap();
private static final Set<String> LEGAL_DISTRIBUTION_LEVELS =
SetUtil.newUnmodifiableStringSet(
Level.SEVERE.toString(), Level.WARNING.toString() );
public Map<String,Integer>
getErrorDistribution(long timestamp, String level)
{
if ( ! LEGAL_DISTRIBUTION_LEVELS.contains( level ) )
{
throw new IllegalArgumentException( level );
}
unimplemented();
Map<String,Integer> result =
null; //getLogMBean().getErrorDistribution( timestamp, Level.parse( level ) );
// query may return null instead of an empty Map
if ( result != null )
{
final Set<String> moduleIDs = result.keySet();
// Ensure that no module has a null count
for( final String moduleID : moduleIDs )
{
if ( result.get( moduleID ) == null )
{
result.put( moduleID, INTEGER_0 );
}
}
}
else
{
// never return a null Map, only an empty one
result = EMPTY_ERROR_DISTRIBUTION_MAP;
}
return result;
}
public void
setKeepErrorStatisticsForIntervals( final int num)
{
unimplemented();
//getLogMBean().setKeepErrorStatisticsForIntervals( num );
}
public int
getKeepErrorStatisticsForIntervals()
{
return 0;
/*
unimplemented();
return getLogMBean().getKeepErrorStatisticsForIntervals();
*/
}
public void
setErrorStatisticsIntervalMinutes(final long minutes)
{
unimplemented();
//getLogMBean().setErrorStatisticsIntervalDuration( minutes );
}
public long
getErrorStatisticsIntervalMinutes()
{
return 0;
/*
unimplemented();
return getLogMBean().getErrorStatisticsIntervalDuration();
*/
}
public String[]
getLoggerNames()
{
return EMPTY_STRING_ARRAY;
/*unimplemented();
final List<String> names =
TypeCast.checkList( getLogMBean().getLoggerNames(), String.class );
return names.toArray( EMPTY_STRING_ARRAY ); */
}
public String[]
getLoggerNamesUnder( final String loggerName )
{
unimplemented();
/*
final List<String> names = TypeCast.checkList(
getLogMBean().getLoggerNamesUnder( loggerName ), String.class );
return names.toArray( EMPTY_STRING_ARRAY );
*/
return null;
}
public String[]
getDiagnosticCauses( final String messageID, final String moduleName )
{
final List<String> causes = msgIdCatalog.getDiagnosticCausesForMessageId( messageID , moduleName );
String[] result = null;
if ( causes != null )
{
result = CollectionUtil.toArray( causes, String.class );
}
return result;
}
public String[]
getDiagnosticChecks( String messageID, String moduleName )
{
final List<String> checks = msgIdCatalog.getDiagnosticChecksForMessageId( messageID , moduleName );
String[] result = null;
if ( checks != null )
{
result = CollectionUtil.toArray( checks, String.class );
}
return result;
}
public String
getDiagnosticURI( final String messageID )
{
unimplemented();
return null; //getLogMBean().getDiagnosticURIForMessageId( messageID );
}
private static final Object[]
LEVELS_AND_NOTIF_TYPES = new Object[]
{
Level.SEVERE, LOG_RECORD_SEVERE_NOTIFICATION_TYPE,
Level.WARNING, LOG_RECORD_WARNING_NOTIFICATION_TYPE,
Level.INFO, LOG_RECORD_INFO_NOTIFICATION_TYPE,
Level.CONFIG, LOG_RECORD_CONFIG_NOTIFICATION_TYPE,
Level.FINE, LOG_RECORD_FINE_NOTIFICATION_TYPE,
Level.FINER, LOG_RECORD_FINER_NOTIFICATION_TYPE,
Level.FINEST, LOG_RECORD_FINEST_NOTIFICATION_TYPE,
};
private static Map<Level,String>
initLevelToNotificationTypeMap()
{
final Map<Level,String> m = new HashMap();
for( int i = 0; i < LEVELS_AND_NOTIF_TYPES.length; i += 2 )
{
final Level level = (Level)LEVELS_AND_NOTIF_TYPES[ i ];
final String notifType = (String)LEVELS_AND_NOTIF_TYPES[ i + 1 ];
m.put( level, notifType );
}
return( Collections.unmodifiableMap( m ) );
}
private String
logLevelToNotificationType( final Level level )
{
String notificationType = mLevelToNotificationTypeMap.get( level );
if ( notificationType == null )
{
}
return notificationType;
}
protected void
preRegisterDone()
throws Exception
{
initNotificationTypeToNotificationBuilderMap( getObjectName() );
}
private void
initNotificationTypeToNotificationBuilderMap( final ObjectName objectName )
{
mNotificationTypeToNotificationBuilderMap.clear();
for( final String notifType : ALL_LOG_RECORD_NOTIFICATION_TYPES )
{
mNotificationTypeToNotificationBuilderMap.put(
notifType,
new NotificationBuilder( notifType, objectName ) );
}
}
private NotificationBuilder
notificationTypeToNotificationBuilder( final String notificationType )
{
NotificationBuilder builder =
mNotificationTypeToNotificationBuilderMap.get( notificationType );
assert( builder != null );
return builder;
}
private Map<String,Serializable>
logRecordToMap(
final LogRecord record,
final String recordAsString )
{
final Map<String,Serializable> m = new HashMap();
m.put( LOG_RECORD_AS_STRING_KEY, recordAsString );
m.put( LOG_RECORD_LEVEL_KEY, record.getLevel() );
m.put( LOG_RECORD_LOGGER_NAME_KEY, record.getLoggerName() );
m.put( LOG_RECORD_MESSAGE_KEY, record.getMessage() );
m.put( LOG_RECORD_MILLIS_KEY, record.getMillis() );
m.put( LOG_RECORD_SEQUENCE_NUMBER_KEY, record.getSequenceNumber() );
m.put( LOG_RECORD_SOURCE_CLASS_NAME_KEY, record.getSourceClassName() );
m.put( LOG_RECORD_SOURCE_METHOD_NAME_KEY, record.getSourceMethodName() );
m.put( LOG_RECORD_THREAD_ID_KEY, record.getThreadID() );
final Throwable thrown = record.getThrown();
if ( thrown != null )
{
final Throwable mapped = new ThrowableMapper( thrown ).map();
m.put( LOG_RECORD_THROWN_KEY, mapped );
final Throwable rootCause = ExceptionUtil.getRootCause( thrown );
if ( rootCause != thrown )
{
final Throwable mappedRootCause = new ThrowableMapper( rootCause ).map();
m.put( LOG_RECORD_ROOT_CAUSE_KEY, mappedRootCause );
}
}
return m;
}
private long mMyThreadID = -1;
/**
Internal use only, called by com.sun.enterprise.server.logging.AMXLoggingHook.
*/
public void
privateLoggingHook(
final LogRecord logRecord,
final Formatter formatter )
{
//debug( "LoggingImpl.privateLoggingHook: " + formatter.format( logRecord ) );
if ( logRecord.getThreadID() == mMyThreadID )
{
debug( "privateLoggingHook: recusive call!!!" );
throw new RuntimeException( "recursive call" );
}
synchronized( this )
{
mMyThreadID = Thread.currentThread().getId();
final Level level = logRecord.getLevel();
try
{
// don't construct a Notification if there are no listeners.
if ( getLogLevelListenerCount( level ) != 0 )
{
final String notifType = logLevelToNotificationType( level );
final NotificationBuilder builder =
notificationTypeToNotificationBuilder( notifType );
// Notification.getMessage() will be the formatted log record
final String logRecordAsString = formatter.format( logRecord );
final Map<String,Serializable> userData =
logRecordToMap( logRecord, logRecordAsString );
final Notification notif =
builder.buildNewWithMap( logRecordAsString, userData);
debug( "privateLoggingHook: sending: " + notif );
sendNotification( notif );
}
else
{
// debug( "privateLogHook: no listeners for level " + level );
}
}
finally
{
mMyThreadID = -1;
}
}
}
public void
testEmitLogMessage( final String level, final String message )
{
final String saveLevel = null; //getMBeanLogLevel();
setMBeanLogLevel( level );
try
{
debug( "testEmitLogMessage: logging: message = " + message );
getLogger().log( Level.parse( level ), message );
}
finally
{
setMBeanLogLevel( saveLevel );
}
}
/**
keep for debugging
private static String cn( Object o ) { return o == null ? "null" : o.getClass().getNameProp(); }
public synchronized void
addNotificationListener(
final NotificationListener listener )
{
super.addNotificationListener( listener );
debug( "LoggingImpl.addNotificationListener: class = " + cn(listener) );
}
public synchronized void
addNotificationListener(
final NotificationListener listener,
final NotificationFilter filter,
final Object handback)
{
super.addNotificationListener( listener, filter, handback );
debug( "LoggingImpl.addNotificationListener: class = " + cn(listener) +
", filter = " + cn(filter) + ", handback = " + cn(handback) );
}
public synchronized void
removeNotificationListener( final NotificationListener listener)
throws javax.management.ListenerNotFoundException
{
super.removeNotificationListener( listener );
debug( "LoggingImpl.removeNotificationListener: class = " + cn(listener) );
}
public synchronized void
removeNotificationListener(
final NotificationListener listener,
final NotificationFilter filter,
final Object handback)
throws javax.management.ListenerNotFoundException
{
super.removeNotificationListener( listener, filter, handback );
debug( "LoggingImpl.removeNotificationListener: class = " + cn(listener) +
", filter = " + cn(filter) + ", handback = " + cn(handback) );
}
*/
}
Other Glassfish examples (source code examples)
Here is a short list of links related to this Glassfish LoggingImpl.java source code file:
|