Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*******************************************************************************
* Copyright (c) 2025 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/

package com.ibm.websphere.ras.annotation;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
* Indicates that a non-static TraceComponent field should be ignored by the
* Liberty bytecode instrumentation tool. This annotation is used in cases where
* a TraceComponent must be instance-specific (non-static) for legitimate reasons,
* such as when different instances need different trace channels or configurations.
* <p>
* Without this annotation, the instrumentation tool will issue a warning and fail
* instrumentation when it encounters a non-static TraceComponent field, as the
* standard pattern requires TraceComponent fields to be declared as
* {@code private static final}.
* <p>
* Example usage:
* <pre>
* public class MyClass {
* // Dummy static TraceComponent to satisfy instrumentation
* private static final TraceComponent tc = Tr.register(MyClass.class);
*
* // Instance-specific TraceComponent that won't trigger instrumentation errors
* &#64;IgnoreNonStaticTraceComponent
* private final TraceComponent instanceTc;
*
* public MyClass(String channelName) {
* this.instanceTc = Tr.register(channelName, MyClass.class, TRACE_GROUP);
* }
* }
* </pre>
*
* @see com.ibm.websphere.ras.TraceComponent
* @see com.ibm.websphere.ras.Tr
*/
@Target({ FIELD })
@Retention(RUNTIME)
public @interface IgnoreNonStaticTraceComponent {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,21 @@

import com.ibm.websphere.ras.Tr;
import com.ibm.websphere.ras.TraceComponent;
import com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent;
import com.ibm.websphere.ras.annotation.Trivial;
import com.ibm.wsspi.persistence.internal.PersistenceServiceConstants;

//TODO(151905) -- Cleanup. Poached from Liberty
@Trivial
class LogChannel {
/*
* WORKAROUND for Liberty bytecode instrumentation limitation:
*
* The instrumentation tool requires TraceComponent fields to be 'private static final'.
* However, this class needs instance-specific trace components for different EclipseLink channels.
*
* Solution: Declare a dummy static TraceComponent to satisfy instrumentation, then store
* the actual instance TraceComponent as Object type (which instrumentation doesn't check).
* The _tc() helper method casts it back to TraceComponent when needed for logging.
*/
// Static TraceComponent for general LogChannel class tracing
private static final TraceComponent _stc = Tr.register(LogChannel.class);
private final Object _tcInstance;

private TraceComponent _tc() {
return (TraceComponent) _tcInstance;
}
// Instance-specific TraceComponent for different EclipseLink channels
// The @IgnoreNonStaticTraceComponent annotation tells the instrumentation tool
// that this non-static field is intentional and should not trigger warnings
@IgnoreNonStaticTraceComponent
private final TraceComponent _tc;

/**
* Log levels (per EclipseLink)
Expand All @@ -57,29 +50,29 @@ private TraceComponent _tc() {
*/
LogChannel(String channel) {
// Register a TraceComponent for this specific channel
_tcInstance = Tr.register(channel, LogChannel.class, PersistenceServiceConstants.TRACE_GROUP);
_tc = Tr.register(channel, LogChannel.class, PersistenceServiceConstants.TRACE_GROUP);
}

boolean shouldLog(int level) {
switch (level) {
case 8:
return false;
case 7: // SEVERE
return _tc().isErrorEnabled();
return _tc.isErrorEnabled();
case 6: // WARN
return _tc().isWarningEnabled();
return _tc.isWarningEnabled();
case 5: // INFO
return _tc().isInfoEnabled();
return _tc.isInfoEnabled();
case 4: // CONFIG
return _tc().isConfigEnabled();
return _tc.isConfigEnabled();
case 3: // FINE
return _tc().isEventEnabled();
return _tc.isEventEnabled();
case 2: // FINER
return _tc().isEntryEnabled();
return _tc.isEntryEnabled();
case 1: // FINEST
case 0: // TRACE
default:
return _tc().isDebugEnabled();
return _tc.isDebugEnabled();
}// end switch
}

Expand All @@ -103,23 +96,23 @@ void log(SessionLogEntry entry, String formattedMessage) {
case 7: // SEVERE
// With the persistence service, only errors will be logged. The rest will be debug.
String errMsg = Tr.formatMessage(_stc, "PROVIDER_ERROR_CWWKD0292E", msgParm);
Tr.error(_tc(), errMsg);
Tr.error(_tc, errMsg);
break;
case 6:// WARN
String wrnMsg = Tr.formatMessage(_stc, "PROVIDER_WARNING_CWWKD0291W", msgParm);
Tr.debug(_tc(), wrnMsg); // 170432 - move warnings to debug
Tr.debug(_tc, wrnMsg); // 170432 - move warnings to debug
break;
case 3: // FINE
case 2: // FINER
case 1: // FINEST
case 0: // TRACE
Tr.debug(_tc(), formattedMessage);
Tr.debug(_tc, formattedMessage);
break;
}// end switch

// if there is an exception - only log it to trace
if (_tc().isDebugEnabled() && loggedException != null) {
Tr.debug(_tc(), "throwable", loggedException);
if (_tc.isDebugEnabled() && loggedException != null) {
Tr.debug(_tc, "throwable", loggedException);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class TraceConfigClassVisitor extends ClassVisitor {
protected final static Type TRIVIAL_TYPE = Type.getType(com.ibm.websphere.ras.annotation.Trivial.class);;
protected final static Type FFDC_IGNORE_TYPE = Type.getType(com.ibm.ws.ffdc.annotation.FFDCIgnore.class);
protected final static Type TRACE_OBJECT_FIELD_TYPE = Type.getType(com.ibm.websphere.ras.annotation.TraceObjectField.class);
protected final static Type IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE = Type.getType(com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent.class);

protected ClassInfo classInfo;
protected TraceOptionsAnnotationVisitor traceOptionsAnnotationVisitor;
Expand Down Expand Up @@ -85,7 +86,34 @@ public FieldVisitor visitField(int access, String name, String desc, String sign
FieldInfo fieldInfo = new FieldInfo(name, desc);
classInfo.addFieldInfo(fieldInfo);
}
return fv;
return new FieldInfoFieldVisitor(fv, name, desc, access);
}

private final static class FieldInfoFieldVisitor extends FieldVisitor {
private final String fieldName;
private final String fieldDesc;
private final int fieldAccess;
private boolean hasIgnoreAnnotation = false;

private FieldInfoFieldVisitor(FieldVisitor fv, String name, String desc, int access) {
super(ASMHelper.getCurrentASM(), fv);
this.fieldName = name;
this.fieldDesc = desc;
this.fieldAccess = access;
}

@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(desc, visible);
if (IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE.getDescriptor().equals(desc)) {
hasIgnoreAnnotation = true;
}
return av;
}

public boolean hasIgnoreAnnotation() {
return hasIgnoreAnnotation;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public class LibertyTracePreprocessInstrumentation extends AbstractInstrumentati
public final static Type INJECTED_TRACE_TYPE = Type.getType(com.ibm.websphere.ras.annotation.InjectedTrace.class);
public final static Type MANUAL_TRACE_TYPE = Type.getType(com.ibm.websphere.ras.annotation.ManualTrace.class);
public final static Type TRACE_OBJECT_FIELD_TYPE = Type.getType(com.ibm.websphere.ras.annotation.TraceObjectField.class);
public final static Type IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE = Type.getType(com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent.class);

private boolean addFfdc = false;
private boolean injectStatic = false;
Expand Down Expand Up @@ -257,7 +258,7 @@ private void processClassTraceOptionsAnnotation(ClassTraceInfo info) {
/**
* Introspect the class to obtain the list of fields declared as {@code com.ibm.websphere.ras.TraceComponent}s. Only static
* declarations are considered.
*
*
* @param info the collected class information
*/
private void processLibertyTraceComponentDiscovery(ClassTraceInfo info) {
Expand All @@ -267,13 +268,27 @@ private void processLibertyTraceComponentDiscovery(ClassTraceInfo info) {
for (int i = traceComponentFields.size() - 1; i >= 0; i--) {
FieldNode fn = traceComponentFields.get(i);
if ((fn.access & Opcodes.ACC_STATIC) != Opcodes.ACC_STATIC) {
// Trace Component fields found, but not static
// Check if the field has the @IgnoreNonStaticTraceComponent annotation
boolean hasIgnoreAnnotation = false;
if (fn.visibleAnnotations != null) {
for (AnnotationNode an : fn.visibleAnnotations) {
if (IGNORE_NON_STATIC_TRACE_COMPONENT_TYPE.getDescriptor().equals(an.desc)) {
hasIgnoreAnnotation = true;
break;
}
}
}

// Trace Component fields found, but not static
traceComponentFields.remove(i);
StringBuilder sb = new StringBuilder();
sb.append("WARNING: TraceComponent field declared but must be static in class: ");
sb.append(info.classNode.name.replaceAll("/", "\\."));
info.warnings.add(sb.toString());
info.failInstrumentation = true;

if (!hasIgnoreAnnotation) {
StringBuilder sb = new StringBuilder();
sb.append("WARNING: TraceComponent field declared but must be static in class: ");
sb.append(info.classNode.name.replaceAll("/", "\\."));
info.warnings.add(sb.toString());
info.failInstrumentation = true;
}
}
}
if (traceComponentFields.size() > 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.ibm.websphere.ras.Tr;
import com.ibm.websphere.ras.TraceComponent;
import com.ibm.websphere.ras.annotation.IgnoreNonStaticTraceComponent;
import com.ibm.ws.security.common.lang.LocalesModifier;

/**
Expand All @@ -25,39 +26,31 @@
* other line is updated at some point.
*/
public class BrowserAndServerLogMessage {
/*
* WORKAROUND for Liberty bytecode instrumentation limitation:
*
* The instrumentation tool requires TraceComponent fields to be 'private static final'.
* However, this class needs instance-specific trace components to support different
* OAuth providers and localized error messages.
*
* Solution: Declare a dummy static TraceComponent to satisfy instrumentation, then store
* the actual instance TraceComponent as Object type (which instrumentation doesn't check).
* The tc() helper method casts it back to TraceComponent when needed for message formatting.
*/
// Static TraceComponent for general class tracing
private static final TraceComponent tcStatic = Tr.register(BrowserAndServerLogMessage.class);
private final Object tcInstance;

// Instance-specific TraceComponent for different OAuth providers
// The @IgnoreNonStaticTraceComponent annotation tells the instrumentation tool
// that this non-static field is intentional and should not trigger warnings
@IgnoreNonStaticTraceComponent
private final TraceComponent tc;

private Enumeration<Locale> requestLocales = null;
private final String msgKey;
private final Object[] inserts;

public BrowserAndServerLogMessage(TraceComponent tc, String msgKey, Object... inserts) {
this.tcInstance = tc;
this.tc = tc;
this.msgKey = msgKey;
this.inserts = inserts;
}

private TraceComponent tc() {
return (TraceComponent) tcInstance;
}

public String getBrowserErrorMessage() {
return Tr.formatMessage(tc(), LocalesModifier.getPrimaryLocale(requestLocales), msgKey, inserts);
return Tr.formatMessage(tc, LocalesModifier.getPrimaryLocale(requestLocales), msgKey, inserts);
}

public String getServerErrorMessage() {
return Tr.formatMessage(tc(), msgKey, inserts);
return Tr.formatMessage(tc, msgKey, inserts);
}

public void setLocales(Enumeration<Locale> requestLocales) {
Expand Down
Loading