Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1972cb5
Replace servlet context logging with JUL logging in com.google.gwt.us…
g-keiser Jun 27, 2025
7593341
Add RPC logging facade backed by service loader
g-keiser Sep 25, 2025
752da22
Add ServletContext parameter to RpcLogger methods, allow only one ini…
g-keiser Dec 10, 2025
8479994
Remove unneeded double-checked locking from RpcLogManager#getLoggerPr…
g-keiser Dec 11, 2025
a193b4b
Added missing prefix to ServletContextLogger#error(String, Throwable,…
g-keiser Dec 11, 2025
ff5c4a4
Remove reflective logger implementations
g-keiser Feb 11, 2026
4c02c1d
Remove accidentally committed logging
g-keiser Feb 11, 2026
aed9365
Add real delegate to RpcLogger constructor instead of trying to lazil…
g-keiser Feb 11, 2026
370a386
Remove manual logger initialization mechanisms
g-keiser Feb 12, 2026
6c56728
Remove redundant atomic for RpcLoggerProvider
g-keiser Feb 12, 2026
949f5ef
Fix link to maven guide
g-keiser Feb 12, 2026
fc0680f
Remove RpcLoggerProvider services file, which is not being packaged p…
g-keiser Feb 12, 2026
68a3b9d
Remove reference to services directory from maven build script
g-keiser Feb 12, 2026
5dd9a4f
Correct continuation indent
g-keiser Feb 12, 2026
72127bc
Remove ServletContext parameter from RpcLogger methods by instead set…
g-keiser Feb 13, 2026
0d09368
Improve javadoc comment
g-keiser Feb 13, 2026
2091f1c
Update javadoc
g-keiser Feb 13, 2026
fd4e266
Merge initialize and get provider methods in RpcLogManager
g-keiser Feb 25, 2026
ece5acf
Revert changes to RemoteServiceServletTest
g-keiser Feb 25, 2026
cecfc97
Remove unneeded layer of indirection by combining RpcLogger and RpcLo…
g-keiser Apr 27, 2026
a0010c1
Remove unneeded locking from logger provider initialization
g-keiser Apr 27, 2026
219daba
Improve documentation of RPC logging package
g-keiser Apr 27, 2026
19969ef
Correct an inaccurate javadoc
g-keiser Apr 28, 2026
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
2 changes: 1 addition & 1 deletion maven/lib-gwt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function maven-gwt() {
zip -q $GWT_EXTRACT_DIR/gwt-user.jar --copy --out $GWT_EXTRACT_DIR/gwt-user-trimmed.jar \
"com/google/gwt/*" "com/google/web/bindery/*" "javaemul/*" \
"javax/validation/*" "org/hibernate/validator/*" \
"org/w3c/flute/*"
"org/w3c/flute/*" "META-INF/services/*"
mv $GWT_EXTRACT_DIR/gwt-user-trimmed.jar $GWT_EXTRACT_DIR/gwt-user.jar

for i in $gwtLibs
Expand Down
19 changes: 19 additions & 0 deletions user/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,24 @@
</tokenfilter>
</filterchain>
</move>
<move file="${project.build}/no-servlet-src/META-INF/services/com.google.gwt.user.server.rpc.logging.LoggerProvider" tofile="${project.build}/jakarta-src/META-INF/services/com.google.gwt.user.server.rpc.logging.jakarta.LoggerProvider">
<filterchain>
<tokenfilter>
<replacestring from="com.google.gwt.user.server.rpc.logging" to="com.google.gwt.user.server.rpc.logging.jakarta"/>
</tokenfilter>
</filterchain>
</move>
<move todir="${project.build}/jakarta-src/com/google/gwt/user/server/rpc/logging/jakarta">
<fileset dir="${project.build}/no-servlet-src/com/google/gwt/user/server/rpc/logging">
<include name="**/*.java"/>
</fileset>
<filterchain>
<tokenfilter>
<replacestring from="package com.google.gwt.user.server.rpc.logging" to="package com.google.gwt.user.server.rpc.logging.jakarta"/>
<replacestring from="javax.servlet" to="jakarta.servlet"/>
</tokenfilter>
</filterchain>
</move>
<move todir="${project.build}/jakarta-src/com/google/gwt/user/server/rpc/jakarta">
<filelist dir="${project.build}/no-servlet-src/com/google/gwt/user/server/rpc">
<file name="AbstractRemoteServiceServlet.java"/>
Expand All @@ -178,6 +196,7 @@
<tokenfilter>
<replacestring from="package com.google.gwt.user.server.rpc" to="package com.google.gwt.user.server.rpc.jakarta"/>
<replacestring from="com.google.gwt.user.server.Util" to="com.google.gwt.user.server.jakarta.Util"/>
<replacestring from="com.google.gwt.user.server.rpc.logging" to="com.google.gwt.user.server.rpc.logging.jakarta"/>
<replacestring from="javax.servlet" to="jakarta.servlet"/>
</tokenfilter>
</filterchain>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
com.google.gwt.user.server.rpc.logging.JulLoggerProvider
com.google.gwt.user.server.rpc.logging.Log4jProvider
com.google.gwt.user.server.rpc.logging.PlatformLoggerProvider
# No no-args constructor: com.google.gwt.user.server.rpc.logging.ServletContextLoggerProvider
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
Expand All @@ -41,9 +40,8 @@ public AbstractRemoteServiceServlet() {
* Standard HttpServlet method: handle the POST. Delegates to
* {@link #processPost(HttpServletRequest, HttpServletResponse)}.
*
* This doPost method swallows ALL exceptions, logs them in the
* ServletContext, and returns a GENERIC_FAILURE_MSG response with status code
* 500.
* This doPost method swallows ALL exceptions, logs them,
* and returns a GENERIC_FAILURE_MSG response with status code 500.
*/
@Override
public final void doPost(HttpServletRequest request,
Expand Down Expand Up @@ -106,9 +104,7 @@ protected void doUnexpectedFailure(Throwable e) {
*/
throw new RuntimeException("Unable to report failure", e);
}
ServletContext servletContext = getServletContext();
RPCServletUtils.writeResponseForUnexpectedFailure(servletContext,
getThreadLocalResponse(), e);
RPCServletUtils.writeResponseForUnexpectedFailure(getThreadLocalResponse(), e);
}

/**
Expand Down
33 changes: 25 additions & 8 deletions user/src/com/google/gwt/user/server/rpc/RPCServletUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
package com.google.gwt.user.server.rpc;


import com.google.gwt.user.server.rpc.logging.LogManager;
import com.google.gwt.user.server.rpc.logging.Logger;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
Expand All @@ -37,6 +40,8 @@
*/
public class RPCServletUtils {

private static final Logger logger = LogManager.getLogger(RPCServletUtils.class);

public static final String CHARSET_UTF8_NAME = "UTF-8";

/**
Expand Down Expand Up @@ -319,20 +324,27 @@ public static boolean shouldGzipResponseContent(HttpServletRequest request,
&& exceedsUncompressedContentLengthLimit(responseContent);
}

@Deprecated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc as to why it is deprecated, what the user should do instead

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer deprecated.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand your reply - perhaps you changed your mind, and it is still deprecated, but now has a comment? Or did you intend to drop this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I changed the way some of this stuff worked and deprecated that again.

public static void writeResponse(ServletContext servletContext,
HttpServletResponse response, String responseContent, boolean gzipResponse)
throws IOException {
writeResponse(response, responseContent, gzipResponse);
}


/**
* Write the response content into the {@link HttpServletResponse}. If
* <code>gzipResponse</code> is <code>true</code>, the response content will
* be gzipped prior to being written into the response.
*
* @param servletContext servlet context for this response
* @param response response instance
* @param responseContent a string containing the response content
* @param gzipResponse if <code>true</code> the response content will be gzip
* encoded before being written into the response
* @throws IOException if reading, writing, or closing the response's output
* stream fails
*/
public static void writeResponse(ServletContext servletContext,
public static void writeResponse(
HttpServletResponse response, String responseContent, boolean gzipResponse)
throws IOException {

Expand Down Expand Up @@ -363,7 +375,7 @@ public static void writeResponse(ServletContext servletContext,
}

if (caught != null) {
servletContext.log("Unable to compress response", caught);
logger.error("Unable to compress response", caught);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
Expand All @@ -378,18 +390,23 @@ public static void writeResponse(ServletContext servletContext,
response.getOutputStream().write(responseBytes);
}

@Deprecated
public static void writeResponseForUnexpectedFailure(
ServletContext servletContext, HttpServletResponse response,
Throwable failure) {
writeResponseForUnexpectedFailure(response, failure);
}

/**
* Called when the servlet itself has a problem, rather than the invoked
* third-party method. It writes a simple 500 message back to the client.
*
* @param servletContext
* @param response
* @param failure
*/
public static void writeResponseForUnexpectedFailure(
ServletContext servletContext, HttpServletResponse response,
Throwable failure) {
servletContext.log("Exception while dispatching incoming RPC call", failure);
HttpServletResponse response, Throwable failure) {
logger.error("Exception while dispatching incoming RPC call", failure);

// Send GENERIC_FAILURE_MSG with 500 status.
//
Expand All @@ -403,7 +420,7 @@ public static void writeResponseForUnexpectedFailure(
response.getWriter().write(GENERIC_FAILURE_MSG);
}
} catch (IOException ex) {
servletContext.log(
logger.error(
"respondWithUnexpectedFailure failed while sending the previous failure to the client",
ex);
}
Expand Down
72 changes: 40 additions & 32 deletions user/src/com/google/gwt/user/server/rpc/RemoteServiceServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.RpcTokenException;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.logging.LogManager;
import com.google.gwt.user.server.rpc.logging.Logger;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -45,6 +47,8 @@
public class RemoteServiceServlet extends AbstractRemoteServiceServlet
implements SerializationPolicyProvider {

private static final Logger logger = LogManager.getLogger(RemoteServiceServlet.class);

/**
* Loads a serialization policy stored as a servlet resource in the same
* ServletContext as this servlet. Returns null if not found.
Expand All @@ -62,7 +66,7 @@ static SerializationPolicy loadSerializationPolicy(HttpServlet servlet,
modulePath = new URL(moduleBaseURL).getPath();
} catch (MalformedURLException ex) {
// log the information, we will default
servlet.log("Malformed moduleBaseURL: " + moduleBaseURL, ex);
logger.error("Malformed moduleBaseURL: " + moduleBaseURL, ex);
}
}

Expand All @@ -74,12 +78,12 @@ static SerializationPolicy loadSerializationPolicy(HttpServlet servlet,
* this method.
*/
if (modulePath == null || !modulePath.startsWith(contextPath)) {
String message = "ERROR: The module path requested, "
String message = "The module path requested, "
+ modulePath
+ ", is not in the same web application as this servlet, "
+ contextPath
+ ". Your module may not be properly configured or your client and server code maybe out of date.";
servlet.log(message);
logger.error(message);
} else {
// Strip off the context path from the module base URL. It should be a
// strict prefix.
Expand All @@ -98,11 +102,13 @@ static SerializationPolicy loadSerializationPolicy(HttpServlet servlet,
null);
if (serializationPolicy.hasClientFields()) {
if (ENABLE_ENHANCED_CLASSES) {
servlet.log("WARNING: Service deserializes enhanced JPA/JDO classes, which is " +
logger.warn(
"Service deserializes enhanced JPA/JDO classes, which is " +
"unsafe. See https://github.com/gwtproject/gwt/issues/9709 for more " +
"detail on the vulnerability that this presents.");
} else {
servlet.log("ERROR: Service deserializes enhanced JPA/JDO classes, which is " +
logger.error(
"Service deserializes enhanced JPA/JDO classes, which is " +
"unsafe. Review build logs to see which classes are affected, or set " +
ENABLE_GWT_ENHANCED_CLASSES_PROPERTY + " to true to allow using this " +
"service. See https://github.com/gwtproject/gwt/issues/9709 for more " +
Expand All @@ -111,17 +117,19 @@ static SerializationPolicy loadSerializationPolicy(HttpServlet servlet,
}
}
} catch (ParseException e) {
servlet.log("ERROR: Failed to parse the policy file '"
logger.error(
"Failed to parse the policy file '"
+ serializationPolicyFilePath + "'", e);
} catch (IOException e) {
servlet.log("ERROR: Could not read the policy file '"
logger.error(
"Could not read the policy file '"
+ serializationPolicyFilePath + "'", e);
}
} else {
String message = "ERROR: The serialization policy file '"
String message = "The serialization policy file '"
+ serializationPolicyFilePath
+ "' was not found; did you forget to include it in this deployment?";
servlet.log(message);
logger.error(message);
}
} finally {
if (is != null) {
Expand Down Expand Up @@ -182,9 +190,22 @@ public RemoteServiceServlet(Object delegate) {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
String providerName = getProviderName(config);
LogManager.initialize(providerName, config.getServletContext());
codeServerPort = getCodeServerPort();
}

private String getProviderName(ServletConfig config) {
String parameterName = "gwt.rpc.logging";
if (System.getProperty(parameterName) != null) {
return System.getProperty(parameterName);
} else if (config.getInitParameter(parameterName) != null) {
return config.getInitParameter(parameterName);
} else {
return config.getServletContext().getInitParameter(parameterName);
}
}

/**
* Returns the value of the gwt.codeserver.port system property, or zero if not defined.
*
Expand Down Expand Up @@ -260,8 +281,8 @@ public final SerializationPolicy getSerializationPolicy(String moduleBaseURL,

if (serializationPolicy == null) {
// Failed to get the requested serialization policy; use the default
log(
"WARNING: Failed to get the SerializationPolicy '"
logger.warn(
"Failed to get the SerializationPolicy '"
+ strongName
+ "' for module '"
+ moduleBaseURL
Expand Down Expand Up @@ -311,7 +332,7 @@ public String processCall(String payload) throws SerializationException {
try {
rpcRequest = RPC.decodeRequest(payload, delegate.getClass(), this);
} catch (IncompatibleRemoteServiceException ex) {
log(
logger.error(
"An IncompatibleRemoteServiceException was thrown while processing this call.",
ex);
return RPC.encodeResponseForFailedRequest(null, ex);
Expand Down Expand Up @@ -350,12 +371,13 @@ public String processCall(RPCRequest rpcRequest) throws SerializationException {
rpcRequest.getParameters(), rpcRequest.getSerializationPolicy(),
rpcRequest.getFlags());
} catch (IncompatibleRemoteServiceException ex) {
log(
logger.error(
"An IncompatibleRemoteServiceException was thrown while processing this call.",
ex);
return RPC.encodeResponseForFailedRequest(rpcRequest, ex);
} catch (RpcTokenException tokenException) {
log("An RpcTokenException was thrown while processing this call.",
logger.error(
"An RpcTokenException was thrown while processing this call.",
tokenException);
return RPC.encodeResponseForFailedRequest(rpcRequest, tokenException);
}
Expand All @@ -364,9 +386,8 @@ public String processCall(RPCRequest rpcRequest) throws SerializationException {
/**
* Standard HttpServlet method: handle the POST.
*
* This doPost method swallows ALL exceptions, logs them in the
* ServletContext, and returns a GENERIC_FAILURE_MSG response with status code
* 500.
* This doPost method swallows ALL exceptions, logs them,
* and returns a GENERIC_FAILURE_MSG response with status code 500.
*
* @throws ServletException
* @throws SerializationException
Expand Down Expand Up @@ -465,19 +486,7 @@ protected String getCodeServerPolicyUrl(String strongName) {
* no authentication. It should only be used during development.</p>
*/
protected SerializationPolicy loadPolicyFromCodeServer(String url) {
SerializationPolicyClient.Logger adapter = new SerializationPolicyClient.Logger() {

@Override
public void logInfo(String message) {
RemoteServiceServlet.this.log(message);
}

@Override
public void logError(String message, Throwable throwable) {
RemoteServiceServlet.this.log(message, throwable);
}
};
return CODE_SERVER_CLIENT.loadPolicy(url, adapter);
return CODE_SERVER_CLIENT.loadPolicy(url);
}

/**
Expand Down Expand Up @@ -541,7 +550,6 @@ private void writeResponse(HttpServletRequest request,
boolean gzipEncode = RPCServletUtils.acceptsGzipEncoding(request)
&& shouldCompressResponse(request, response, responsePayload);

RPCServletUtils.writeResponse(getServletContext(), response,
responsePayload, gzipEncode);
RPCServletUtils.writeResponse(response, responsePayload, gzipEncode);
}
}
Loading