View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.internal.injection.full;
7   
8   import static java.util.Collections.enumeration;
9   
10  import edu.umd.cs.findbugs.annotations.NonNull;
11  
12  import jakarta.servlet.Filter;
13  import jakarta.servlet.FilterRegistration;
14  import jakarta.servlet.RequestDispatcher;
15  import jakarta.servlet.Servlet;
16  import jakarta.servlet.ServletContext;
17  import jakarta.servlet.ServletRegistration;
18  import jakarta.servlet.ServletRegistration.Dynamic;
19  import jakarta.servlet.SessionCookieConfig;
20  import jakarta.servlet.SessionTrackingMode;
21  import jakarta.servlet.descriptor.JspConfigDescriptor;
22  import jakarta.servlet.http.HttpSession;
23  
24  import java.io.InputStream;
25  import java.math.BigInteger;
26  import java.net.URL;
27  import java.security.SecureRandom;
28  import java.util.Enumeration;
29  import java.util.EventListener;
30  import java.util.HashMap;
31  import java.util.Map;
32  import java.util.Set;
33  
34  import mockit.internal.injection.InjectionPoint;
35  import mockit.internal.injection.InjectionState;
36  
37  /**
38   * Detects and resolves dependencies belonging to the <code>jakarta.servlet</code> API, namely
39   * <code>ServletContext</code> and <code>HttpSession</code>.
40   */
41  final class ServletJakartaDependencies {
42      // Use a single SecureRandom instance for all sessions
43      private static final SecureRandom SECURE_RANDOM = new SecureRandom();
44  
45      static boolean isApplicable(@NonNull Class<?> dependencyType) {
46          return dependencyType == HttpSession.class || dependencyType == ServletContext.class;
47      }
48  
49      @NonNull
50      private final InjectionState injectionState;
51  
52      ServletJakartaDependencies(@NonNull InjectionState injectionState) {
53          this.injectionState = injectionState;
54      }
55  
56      @NonNull
57      Object createAndRegisterDependency(@NonNull Class<?> dependencyType) {
58          if (dependencyType == ServletContext.class) {
59              return createAndRegisterServletContext();
60          }
61  
62          return createAndRegisterHttpSession();
63      }
64  
65      @NonNull
66      private ServletContext createAndRegisterServletContext() {
67          ServletContext context = new ServletContext() {
68              private final Map<String, String> init = new HashMap<>();
69              private final Map<String, Object> attrs = new HashMap<>();
70  
71              @Override
72              public String getContextPath() {
73                  return "";
74              }
75  
76              @Override
77              public ServletContext getContext(String uriPath) {
78                  return null;
79              }
80  
81              @Override
82              public int getMajorVersion() {
83                  return 3;
84              }
85  
86              @Override
87              public int getMinorVersion() {
88                  return 0;
89              }
90  
91              @Override
92              public int getEffectiveMajorVersion() {
93                  return 3;
94              }
95  
96              @Override
97              public int getEffectiveMinorVersion() {
98                  return 0;
99              }
100 
101             @Override
102             public String getMimeType(String file) {
103                 return null;
104             }
105 
106             @Override
107             public String getRealPath(String path) {
108                 return null;
109             }
110 
111             @Override
112             public Set<String> getResourcePaths(String path) {
113                 return null;
114             }
115 
116             @Override
117             public URL getResource(String path) {
118                 return getClass().getResource(path);
119             }
120 
121             @Override
122             public InputStream getResourceAsStream(String path) {
123                 return getClass().getResourceAsStream(path);
124             }
125 
126             @Override
127             public RequestDispatcher getRequestDispatcher(String path) {
128                 return null;
129             }
130 
131             @Override
132             public RequestDispatcher getNamedDispatcher(String name) {
133                 return null;
134             }
135 
136             @Override
137             public String getServletContextName() {
138                 return null;
139             }
140 
141             @Override
142             public String getServerInfo() {
143                 return "JMockit 1.x";
144             }
145 
146             @Override
147             public ClassLoader getClassLoader() {
148                 return getClass().getClassLoader();
149             }
150 
151             @Override
152             public void log(String msg) {
153             }
154 
155             @Override
156             public void log(String message, Throwable throwable) {
157             }
158 
159             // Context initialization parameters.
160             @Override
161             public Enumeration<String> getInitParameterNames() {
162                 return enumeration(init.keySet());
163             }
164 
165             @Override
166             public String getInitParameter(String name) {
167                 return init.get(name);
168             }
169 
170             @Override
171             public boolean setInitParameter(String name, String value) {
172                 return init.put(name, value) == null;
173             }
174 
175             // Context attributes.
176             @Override
177             public Enumeration<String> getAttributeNames() {
178                 return enumeration(attrs.keySet());
179             }
180 
181             @Override
182             public Object getAttribute(String name) {
183                 return attrs.get(name);
184             }
185 
186             @Override
187             public void setAttribute(String name, Object value) {
188                 attrs.put(name, value);
189             }
190 
191             @Override
192             public void removeAttribute(String name) {
193                 attrs.remove(name);
194             }
195 
196             // Un-implemented methods, which may get a non-empty implementation eventually.
197             @Override
198             public ServletRegistration.Dynamic addServlet(String name, String className) {
199                 return null;
200             }
201 
202             @Override
203             public ServletRegistration.Dynamic addServlet(String name, Servlet servlet) {
204                 return null;
205             }
206 
207             @Override
208             public ServletRegistration.Dynamic addServlet(String nm, Class<? extends Servlet> c) {
209                 return null;
210             }
211 
212             @Override
213             public <T extends Servlet> T createServlet(Class<T> clazz) {
214                 return null;
215             }
216 
217             @Override
218             public ServletRegistration getServletRegistration(String servletName) {
219                 return null;
220             }
221 
222             @Override
223             public Map<String, ? extends ServletRegistration> getServletRegistrations() {
224                 return null;
225             }
226 
227             @Override
228             public FilterRegistration.Dynamic addFilter(String name, String className) {
229                 return null;
230             }
231 
232             @Override
233             public FilterRegistration.Dynamic addFilter(String name, Filter filter) {
234                 return null;
235             }
236 
237             @Override
238             public FilterRegistration.Dynamic addFilter(String name, Class<? extends Filter> cl) {
239                 return null;
240             }
241 
242             @Override
243             public <T extends Filter> T createFilter(Class<T> clazz) {
244                 return null;
245             }
246 
247             @Override
248             public FilterRegistration getFilterRegistration(String filterName) {
249                 return null;
250             }
251 
252             @Override
253             public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
254                 return null;
255             }
256 
257             @Override
258             public SessionCookieConfig getSessionCookieConfig() {
259                 return null;
260             }
261 
262             @Override
263             public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) {
264             }
265 
266             @Override
267             public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
268                 return null;
269             }
270 
271             @Override
272             public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
273                 return null;
274             }
275 
276             @Override
277             public void addListener(String className) {
278             }
279 
280             @Override
281             public <T extends EventListener> void addListener(T t) {
282             }
283 
284             @Override
285             public void addListener(Class<? extends EventListener> listenerClass) {
286             }
287 
288             @Override
289             public <T extends EventListener> T createListener(Class<T> clazz) {
290                 return null;
291             }
292 
293             @Override
294             public JspConfigDescriptor getJspConfigDescriptor() {
295                 return null;
296             }
297 
298             @Override
299             public void declareRoles(String... roleNames) {
300             }
301 
302             @Override
303             public String getVirtualServerName() {
304                 return null;
305             }
306 
307             // Allow older servlet still (no overrides)
308             @Override
309             public Dynamic addJspFile(String servletName, String jspFile) {
310                 return null;
311             }
312 
313             @Override
314             public int getSessionTimeout() {
315                 return 0;
316             }
317 
318             @Override
319             public void setSessionTimeout(int sessionTimeout) {
320             }
321 
322             @Override
323             public String getRequestCharacterEncoding() {
324                 return null;
325             }
326 
327             @Override
328             public void setRequestCharacterEncoding(String encoding) {
329             }
330 
331             @Override
332             public String getResponseCharacterEncoding() {
333                 return null;
334             }
335 
336             @Override
337             public void setResponseCharacterEncoding(String encoding) {
338             }
339         };
340 
341         InjectionPoint injectionPoint = new InjectionPoint(ServletContext.class);
342         InjectionState.saveGlobalDependency(injectionPoint, context);
343         return context;
344     }
345 
346     @NonNull
347     private HttpSession createAndRegisterHttpSession() {
348         HttpSession session = new HttpSession() {
349             // Generate a secure random session ID (32 hex chars)
350             private final String id = new BigInteger(130, SECURE_RANDOM).toString(32);
351             private final long creationTime = System.currentTimeMillis();
352             private final Map<String, Object> attrs = new HashMap<>();
353             private int maxInactiveInterval;
354             private boolean invalidated;
355 
356             @Override
357             public String getId() {
358                 return id;
359             }
360 
361             @Override
362             public int getMaxInactiveInterval() {
363                 return maxInactiveInterval;
364             }
365 
366             @Override
367             public void setMaxInactiveInterval(int interval) {
368                 maxInactiveInterval = interval;
369             }
370 
371             @Override
372             public long getCreationTime() {
373                 checkValid();
374                 return creationTime;
375             }
376 
377             @Override
378             public long getLastAccessedTime() {
379                 checkValid();
380                 return creationTime;
381             }
382 
383             @Override
384             public boolean isNew() {
385                 checkValid();
386                 return false;
387             }
388 
389             @Override
390             public Enumeration<String> getAttributeNames() {
391                 checkValid();
392                 return enumeration(attrs.keySet());
393             }
394 
395             @Override
396             public Object getAttribute(String name) {
397                 checkValid();
398                 return attrs.get(name);
399             }
400 
401             @Override
402             public void setAttribute(String name, Object value) {
403                 checkValid();
404                 attrs.put(name, value);
405             }
406 
407             @Override
408             public void removeAttribute(String name) {
409                 checkValid();
410                 attrs.remove(name);
411             }
412 
413             @Override
414             public void invalidate() {
415                 checkValid();
416                 attrs.clear();
417                 invalidated = true;
418             }
419 
420             private void checkValid() {
421                 if (invalidated) {
422                     throw new IllegalStateException("Session is invalid");
423                 }
424             }
425 
426             @Override
427             public ServletContext getServletContext() {
428                 ServletContext context = InjectionState.getGlobalDependency(new InjectionPoint(ServletContext.class));
429 
430                 if (context == null) {
431                     context = createAndRegisterServletContext();
432                 }
433 
434                 return context;
435             }
436 
437         };
438 
439         InjectionPoint injectionPoint = new InjectionPoint(HttpSession.class);
440         injectionState.saveInstantiatedDependency(injectionPoint, session);
441         return session;
442     }
443 }