1 /*
2  * Zed Attack Proxy (ZAP) and its related class files.
3  *
4  * ZAP is an HTTP/HTTPS proxy for assessing web application security.
5  *
6  * Copyright 2015 The ZAP Development Team
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 package org.parosproxy.paros.extension.option;
21 
22 import java.awt.BorderLayout;
23 import java.awt.GridBagLayout;
24 import java.io.IOException;
25 import java.nio.charset.StandardCharsets;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.Paths;
29 import java.util.List;
30 import javax.swing.JLabel;
31 import javax.swing.JPanel;
32 import javax.swing.JSeparator;
33 import javax.swing.SwingConstants;
34 import org.parosproxy.paros.Constant;
35 import org.parosproxy.paros.view.AbstractParamPanel;
36 import org.parosproxy.paros.view.View;
37 import org.zaproxy.zap.utils.ZapLabel;
38 import org.zaproxy.zap.utils.ZapTextField;
39 import org.zaproxy.zap.view.LayoutHelper;
40 import org.zaproxy.zap.view.renderer.SizeBytesStringValue;
41 
42 /**
43  * The JVM options panel.
44  *
45  * <p>These options are used by zap.sh and zap.bat when starting ZAP
46  */
47 public class OptionsJvmPanel extends AbstractParamPanel {
48 
49     private static final long serialVersionUID = -7541236934312940852L;
50     private static final Path JVM_PROPERTIES_FILE =
51             Paths.get(Constant.getDefaultHomeDirectory(false), ".ZAP_JVM.properties");
52 
53     /** The name of the options panel. */
54     private static final String NAME = Constant.messages.getString("jvm.options.title");
55 
56     private static final SizeBytesStringValue sbsv = new SizeBytesStringValue(false);
57 
58     /** The text field for the JVM options. */
59     private ZapTextField jvmOptionsField = null;
60 
61     private ZapLabel sizeMemoryLabel = null;
62     private ZapLabel usedMemoryLabel = null;
63     private ZapLabel maxMemoryLabel = null;
64 
OptionsJvmPanel()65     public OptionsJvmPanel() {
66         super();
67         setName(NAME);
68         setLayout(new BorderLayout());
69 
70         JPanel panel = new JPanel();
71         panel.setLayout(new GridBagLayout());
72 
73         int row = 0;
74         JLabel jvmOptionsLabel =
75                 new JLabel(Constant.messages.getString("jvm.options.label.jvmoptions"));
76         jvmOptionsLabel.setLabelFor(getJvmOptionsField());
77 
78         panel.add(jvmOptionsLabel, LayoutHelper.getGBC(0, row, 1, 2.0));
79         panel.add(getJvmOptionsField(), LayoutHelper.getGBC(1, row, 1, 8.0));
80 
81         panel.add(
82                 new JLabel(Constant.messages.getString("jvm.options.warning.restart")),
83                 LayoutHelper.getGBC(0, ++row, 2, 1.0));
84 
85         panel.add(
86                 new JSeparator(SwingConstants.HORIZONTAL),
87                 LayoutHelper.getGBC(0, ++row, 2, 0.0D, 0.0D));
88 
89         panel.add(getSizeMemoryLabel(), LayoutHelper.getGBC(0, ++row, 2, 1.0));
90         panel.add(getUsedMemoryLabel(), LayoutHelper.getGBC(0, ++row, 2, 1.0));
91         panel.add(getMaxMemoryLabel(), LayoutHelper.getGBC(0, ++row, 2, 1.0));
92 
93         panel.add(new JLabel(), LayoutHelper.getGBC(0, 10, 1, 0.5D, 1.0D)); // Spacer
94 
95         this.add(panel);
96     }
97 
getJvmOptionsField()98     private ZapTextField getJvmOptionsField() {
99         if (jvmOptionsField == null) {
100             jvmOptionsField = new ZapTextField();
101         }
102         return jvmOptionsField;
103     }
104 
getSizeMemoryLabel()105     private ZapLabel getSizeMemoryLabel() {
106         if (sizeMemoryLabel == null) {
107             sizeMemoryLabel = new ZapLabel();
108         }
109         return sizeMemoryLabel;
110     }
111 
getUsedMemoryLabel()112     private ZapLabel getUsedMemoryLabel() {
113         if (usedMemoryLabel == null) {
114             usedMemoryLabel = new ZapLabel();
115         }
116         return usedMemoryLabel;
117     }
118 
getMaxMemoryLabel()119     private ZapLabel getMaxMemoryLabel() {
120         if (maxMemoryLabel == null) {
121             maxMemoryLabel = new ZapLabel();
122         }
123         return maxMemoryLabel;
124     }
125 
updateMemoryLabel(ZapLabel labelToUpdate, String key, long value)126     private void updateMemoryLabel(ZapLabel labelToUpdate, String key, long value) {
127         labelToUpdate.setText(Constant.messages.getString(key, sbsv.getString(value)));
128     }
129 
130     @Override
initParam(Object obj)131     public void initParam(Object obj) {
132         long size = Runtime.getRuntime().totalMemory();
133         // initParam happens before display of the panel so the values are appropriately set when
134         // viewed
135         updateMemoryLabel(getSizeMemoryLabel(), "jvm.options.memory.size", size);
136         updateMemoryLabel(
137                 getUsedMemoryLabel(),
138                 "jvm.options.memory.used",
139                 size - Runtime.getRuntime().freeMemory());
140         updateMemoryLabel(
141                 getMaxMemoryLabel(), "jvm.options.memory.max", Runtime.getRuntime().maxMemory());
142         try {
143             /* JVM properties are unusual in that they are held
144              * in a separate file from the other options.
145              * This is for various reasons, including the fact they are used
146              * by the scripts rather than the java code.
147              */
148             if (Files.exists(JVM_PROPERTIES_FILE)) {
149                 List<String> lines =
150                         Files.readAllLines(JVM_PROPERTIES_FILE, StandardCharsets.UTF_8);
151                 if (lines.size() > 0) {
152                     getJvmOptionsField().setText(lines.get(0));
153                 }
154             }
155         } catch (IOException e) {
156             // Ignore
157         }
158     }
159 
160     @Override
reset()161     public void reset() {
162         getJvmOptionsField().setText("");
163         saveJvmFile();
164     }
165 
166     @Override
saveParam(Object obj)167     public void saveParam(Object obj) throws Exception {
168         saveJvmFile();
169     }
170 
saveJvmFile()171     private void saveJvmFile() {
172         try {
173             String opts = getJvmOptionsField().getText();
174             if (opts.length() == 0) {
175                 // Delete the file so that the 'normal' defaults apply
176                 Files.deleteIfExists(JVM_PROPERTIES_FILE);
177             } else {
178                 if (!JVM_PROPERTIES_FILE.getParent().toFile().exists()) {
179                     // Can happen if the user has only run the dev version not the release one
180                     JVM_PROPERTIES_FILE.getParent().toFile().mkdirs();
181                 }
182                 // Replace the file contents, even if its just with whitespace
183                 Files.write(JVM_PROPERTIES_FILE, opts.getBytes(StandardCharsets.UTF_8));
184             }
185         } catch (IOException e) {
186             View.getSingleton()
187                     .showWarningDialog(
188                             this,
189                             Constant.messages.getString(
190                                     "jvm.options.error.writing",
191                                     JVM_PROPERTIES_FILE.toAbsolutePath(),
192                                     e.getMessage()));
193         }
194     }
195 
196     @Override
getHelpIndex()197     public String getHelpIndex() {
198         return "ui.dialogs.options.jvm";
199     }
200 }
201