1 /*
2 * Copyright (c) 2002-2025 Gargoyle Software Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit.javascript.background;
16
17 import java.lang.ref.WeakReference;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.htmlunit.Page;
22 import org.htmlunit.WebWindow;
23 import org.htmlunit.html.HtmlPage;
24
25 /**
26 * A JavaScript-triggered background job representing the execution of some JavaScript code.
27 *
28 * @author Daniel Gredler
29 * @author Ronald Brill
30 * @author Sven Strickroth
31 */
32 abstract class JavaScriptExecutionJob extends BasicJavaScriptJob {
33
34 /** Logging support. */
35 private static final Log LOG = LogFactory.getLog(JavaScriptExecutionJob.class);
36
37 /** The label for this job. */
38 private final String label_;
39
40 /** The window to which this job belongs (weakly referenced, so as not to leak memory). */
41 private final WeakReference<WebWindow> window_;
42
43 /**
44 * Creates a new JavaScript execution job, where the JavaScript code to execute is a string.
45 * @param initialDelay the initial amount of time to wait before executing this job
46 * @param period the amount of time to wait between executions of this job (perhaps {@code null})
47 * @param label the label for the job
48 * @param window the window to which the job belongs
49 */
50 JavaScriptExecutionJob(final int initialDelay, final Integer period, final String label,
51 final WebWindow window) {
52 super(initialDelay, period);
53 label_ = label;
54 window_ = new WeakReference<>(window);
55 }
56
57 /** {@inheritDoc} */
58 @Override
59 public void run() {
60 final WebWindow w = window_.get();
61 if (w == null) {
62 // The window has been garbage collected! No need to execute, obviously.
63 return;
64 }
65
66 if (LOG.isDebugEnabled()) {
67 LOG.debug("Executing " + this + ".");
68 }
69
70 try {
71 // Verify that the window is still open
72 if (w.isClosed()) {
73 LOG.debug("Enclosing window is now closed. Execution cancelled.");
74 return;
75 }
76 if (!w.getWebClient().containsWebWindow(w)) {
77 LOG.debug("Enclosing window is now closed. Execution cancelled.");
78 return;
79 }
80
81 // Verify that the current page is still available and a html page
82 final Page enclosedPage = w.getEnclosedPage();
83 if (enclosedPage == null || !enclosedPage.isHtmlPage()) {
84 if (enclosedPage == null) {
85 LOG.debug("The page that originated this job doesn't exist anymore. Execution cancelled.");
86 return;
87 }
88 if (LOG.isDebugEnabled()) {
89 LOG.debug("The page that originated this job is no html page ("
90 + enclosedPage.getClass().getName() + "). Execution cancelled.");
91 }
92 return;
93 }
94
95 runJavaScript((HtmlPage) enclosedPage);
96 }
97 finally {
98 if (LOG.isDebugEnabled()) {
99 LOG.debug("Finished executing " + this + ".");
100 }
101 }
102 }
103
104 /** {@inheritDoc} */
105 @Override
106 public String toString() {
107 return "JavaScript Execution Job " + getId() + ": " + label_;
108 }
109
110 /**
111 * Run the JavaScript from the concrete class.
112 * @param page the {@link HtmlPage} that owns the script
113 */
114 protected abstract void runJavaScript(HtmlPage page);
115 }