Skip to content

Commit 4052087

Browse files
ludochgae-java-bot
authored andcommitted
Introduce Jakarta Servlet API compatible versions of App Engine dev server components.
PiperOrigin-RevId: 805478051 Change-Id: Ieee1c23184f6eff13b4c2d20b22db86ad27e2b22
1 parent e0d81c7 commit 4052087

57 files changed

Lines changed: 1213 additions & 1010 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/src/main/java/com/google/apphosting/utils/servlet/ee10/DeferredTaskServlet.java

Lines changed: 4 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -16,222 +16,9 @@
1616

1717
package com.google.apphosting.utils.servlet.ee10;
1818

19-
import com.google.appengine.api.taskqueue.DeferredTask;
20-
import com.google.appengine.api.taskqueue.ee10.DeferredTaskContext;
21-
import com.google.apphosting.api.ApiProxy;
22-
import jakarta.servlet.ServletException;
23-
import jakarta.servlet.ServletInputStream;
24-
import jakarta.servlet.http.HttpServlet;
25-
import jakarta.servlet.http.HttpServletRequest;
26-
import jakarta.servlet.http.HttpServletResponse;
27-
import java.io.IOException;
28-
import java.io.ObjectInputStream;
29-
import java.io.ObjectStreamClass;
30-
import java.lang.reflect.Modifier;
31-
import java.lang.reflect.Proxy;
32-
import java.net.HttpURLConnection;
33-
import java.util.Map;
34-
3519
/**
36-
* Implementation of {@link HttpServlet} to dispatch tasks with a {@link DeferredTask} payload; see
37-
* {@link com.google.appengine.api.taskqueue.TaskOptions#payload(DeferredTask)}.
38-
*
39-
* <p>This servlet is mapped to {@link DeferredTaskContext#DEFAULT_DEFERRED_URL} by default. Below
40-
* is a snippet of the web.xml configuration.<br>
41-
*
42-
* <pre>
43-
* &lt;servlet&gt;
44-
* &lt;servlet-name&gt;/_ah/queue/__deferred__&lt;/servlet-name&gt;
45-
* &lt;servlet-class
46-
* &gt;com.google.apphosting.utils.servlet.DeferredTaskServlet&lt;/servlet-class&gt;
47-
* &lt;/servlet&gt;
48-
*
49-
* &lt;servlet-mapping&gt;
50-
* &lt;servlet-name&gt;_ah_queue_deferred&lt;/servlet-name&gt;
51-
* &lt;url-pattern&gt;/_ah/queue/__deferred__&lt;/url-pattern&gt;
52-
* &lt;/servlet-mapping&gt;
53-
* </pre>
54-
*
20+
* @deprecated as of version 3.0, use generic com.google.apphosting.utils.servlet.jakarta package.
5521
*/
56-
public class DeferredTaskServlet extends HttpServlet {
57-
// Keep this in sync with X_APPENGINE_QUEUENAME and
58-
// in google3/apphosting/base/http_proto.cc
59-
static final String X_APPENGINE_QUEUENAME = "X-AppEngine-QueueName";
60-
61-
static final String DEFERRED_TASK_SERVLET_KEY =
62-
DeferredTaskContext.class.getName() + ".httpServlet";
63-
static final String DEFERRED_TASK_REQUEST_KEY =
64-
DeferredTaskContext.class.getName() + ".httpServletRequest";
65-
static final String DEFERRED_TASK_RESPONSE_KEY =
66-
DeferredTaskContext.class.getName() + ".httpServletResponse";
67-
static final String DEFERRED_DO_NOT_RETRY_KEY =
68-
DeferredTaskContext.class.getName() + ".doNotRetry";
69-
static final String DEFERRED_MARK_RETRY_KEY = DeferredTaskContext.class.getName() + ".markRetry";
70-
71-
/** Thrown by readRequest when an error occurred during deserialization. */
72-
protected static class DeferredTaskException extends Exception {
73-
public DeferredTaskException(Exception e) {
74-
super(e);
75-
}
76-
}
77-
78-
@Override
79-
protected void service(HttpServletRequest req, HttpServletResponse resp)
80-
throws ServletException, IOException {
81-
// See http://b/3479189. All task queue requests have the X-AppEngine-QueueName
82-
// header set. Non admin users cannot set this header so it's a signal that
83-
// this came from task queue or an admin smart enough to set the header.
84-
if (req.getHeader(X_APPENGINE_QUEUENAME) == null) {
85-
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Not a taskqueue request.");
86-
return;
87-
}
88-
89-
String method = req.getMethod();
90-
if (!method.equals("POST")) {
91-
String protocol = req.getProtocol();
92-
String msg = "DeferredTaskServlet does not support method: " + method;
93-
if (protocol.endsWith("1.1")) {
94-
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
95-
} else {
96-
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
97-
}
98-
return;
99-
}
100-
101-
// Place the current servlet, request and response in the environment for
102-
// situations where the task may need to get to it.
103-
Map<String, Object> attributes = ApiProxy.getCurrentEnvironment().getAttributes();
104-
attributes.put(DEFERRED_TASK_SERVLET_KEY, this);
105-
attributes.put(DEFERRED_TASK_REQUEST_KEY, req);
106-
attributes.put(DEFERRED_TASK_RESPONSE_KEY, resp);
107-
attributes.put(DEFERRED_MARK_RETRY_KEY, false);
108-
109-
try {
110-
performRequest(req, resp);
111-
if ((Boolean) attributes.get(DEFERRED_MARK_RETRY_KEY)) {
112-
resp.setStatus(HttpURLConnection.HTTP_INTERNAL_ERROR);
113-
} else {
114-
resp.setStatus(HttpURLConnection.HTTP_OK);
115-
}
116-
} catch (DeferredTaskException e) {
117-
resp.setStatus(HttpURLConnection.HTTP_UNSUPPORTED_TYPE);
118-
log("Deferred task failed exception: " + e);
119-
return;
120-
} catch (RuntimeException e) {
121-
Boolean doNotRetry = (Boolean) attributes.get(DEFERRED_DO_NOT_RETRY_KEY);
122-
if (doNotRetry == null || !doNotRetry) {
123-
throw new ServletException(e);
124-
} else if (doNotRetry) {
125-
resp.setStatus(HttpURLConnection.HTTP_NOT_AUTHORITATIVE); // Alternate success code.
126-
log(
127-
DeferredTaskServlet.class.getName()
128-
+ " - Deferred task failed but doNotRetry specified. Exception: "
129-
+ e);
130-
}
131-
} finally {
132-
// Clean out the attributes.
133-
attributes.remove(DEFERRED_TASK_SERVLET_KEY);
134-
attributes.remove(DEFERRED_TASK_REQUEST_KEY);
135-
attributes.remove(DEFERRED_TASK_RESPONSE_KEY);
136-
attributes.remove(DEFERRED_DO_NOT_RETRY_KEY);
137-
}
138-
}
139-
140-
/**
141-
* Performs a task enqueued with {@link TaskOptions#payload(DeferredTask)} by deserializing the
142-
* input stream of the {@link HttpServletRequest}.
143-
*
144-
* @param req The HTTP request.
145-
* @param resp The HTTP response.
146-
* @throws DeferredTaskException If an error occurred while deserializing the task.
147-
* <p>Note that other exceptions may be thrown by the {@link DeferredTask#run()} method.
148-
*/
149-
protected void performRequest(HttpServletRequest req, HttpServletResponse resp)
150-
throws DeferredTaskException {
151-
readRequest(req, resp).run();
152-
}
153-
154-
/**
155-
* De-serializes the {@link DeferredTask} object from the input stream.
156-
*
157-
* @throws DeferredTaskException With the chained exception being one of the following:
158-
* <li>{@link IllegalArgumentException}: Indicates a content-type header mismatch.
159-
* <li>{@link ClassNotFoundException}: Deserialization failure.
160-
* <li>{@link IOException}: Deserialization failure.
161-
* <li>{@link ClassCastException}: Deserialization failure.
162-
*/
163-
protected Runnable readRequest(HttpServletRequest req, HttpServletResponse resp)
164-
throws DeferredTaskException {
165-
String contentType = req.getHeader("content-type");
166-
if (contentType == null
167-
|| !contentType.equals(DeferredTaskContext.RUNNABLE_TASK_CONTENT_TYPE)) {
168-
throw new DeferredTaskException(
169-
new IllegalArgumentException(
170-
"Invalid content-type header."
171-
+ " received: '"
172-
+ (String.valueOf(contentType))
173-
+ "' expected: '"
174-
+ DeferredTaskContext.RUNNABLE_TASK_CONTENT_TYPE
175-
+ "'"));
176-
}
177-
178-
try {
179-
ServletInputStream stream = req.getInputStream();
180-
ObjectInputStream objectStream =
181-
new ObjectInputStream(stream) {
182-
@Override
183-
protected Class<?> resolveClass(ObjectStreamClass desc)
184-
throws IOException, ClassNotFoundException {
185-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
186-
String name = desc.getName();
187-
try {
188-
return Class.forName(name, false, classLoader);
189-
} catch (ClassNotFoundException ex) {
190-
// This one should also handle primitive types
191-
return super.resolveClass(desc);
192-
}
193-
}
194-
195-
@Override
196-
protected Class<?> resolveProxyClass(String[] interfaces)
197-
throws IOException, ClassNotFoundException {
198-
// Note This logic was copied from ObjectInputStream.java in the
199-
// JDK, and then modified to use the thread context class loader instead of the
200-
// "latest" loader that is used there.
201-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
202-
ClassLoader nonPublicLoader = null;
203-
boolean hasNonPublicInterface = false;
204-
205-
// define proxy in class loader of non-public interface(s), if any
206-
Class<?>[] classObjs = new Class<?>[interfaces.length];
207-
for (int i = 0; i < interfaces.length; i++) {
208-
Class<?> cl = Class.forName(interfaces[i], false, classLoader);
209-
if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
210-
if (hasNonPublicInterface) {
211-
if (nonPublicLoader != cl.getClassLoader()) {
212-
throw new IllegalAccessError(
213-
"conflicting non-public interface class loaders");
214-
}
215-
} else {
216-
nonPublicLoader = cl.getClassLoader();
217-
hasNonPublicInterface = true;
218-
}
219-
}
220-
classObjs[i] = cl;
221-
}
222-
try {
223-
return Proxy.getProxyClass(
224-
hasNonPublicInterface ? nonPublicLoader : classLoader, classObjs);
225-
} catch (IllegalArgumentException e) {
226-
throw new ClassNotFoundException(null, e);
227-
}
228-
}
229-
};
230-
// Replacing DeferredTask to Runnable as we have DeferredTask in the 2 classloaders
231-
// (runtime and application), but we cannot cast one with another one.
232-
return (Runnable) objectStream.readObject();
233-
} catch (ClassNotFoundException | IOException | ClassCastException e) {
234-
throw new DeferredTaskException(e);
235-
}
236-
}
237-
}
22+
@Deprecated
23+
public class DeferredTaskServlet
24+
extends com.google.apphosting.utils.servlet.jakarta.DeferredTaskServlet {}

0 commit comments

Comments
 (0)