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