server
Clone or download
Modified Files
package com.stream_pi.server.window.settings;
package com.stream_pi.server.window.settings;
import com.stream_pi.server.connection.ServerListener;
import com.stream_pi.server.connection.ServerListener;
import com.stream_pi.server.io.Config;
import com.stream_pi.server.io.Config;
import com.stream_pi.server.window.ExceptionAndAlertHandler;
import com.stream_pi.server.window.ExceptionAndAlertHandler;
import com.stream_pi.server.info.ServerInfo;
import com.stream_pi.server.info.ServerInfo;
import com.stream_pi.util.alert.StreamPiAlert;
import com.stream_pi.util.alert.StreamPiAlert;
import com.stream_pi.util.alert.StreamPiAlertType;
import com.stream_pi.util.alert.StreamPiAlertType;
import com.stream_pi.util.exception.MinorException;
import com.stream_pi.util.exception.MinorException;
import com.stream_pi.util.exception.SevereException;
import com.stream_pi.util.exception.SevereException;
import com.stream_pi.util.startatboot.SoftwareType;
import com.stream_pi.util.startatboot.SoftwareType;
import com.stream_pi.util.startatboot.StartAtBoot;
import com.stream_pi.util.startatboot.StartAtBoot;
import com.stream_pi.util.version.Version;
import com.stream_pi.util.version.Version;
import javafx.application.HostServices;
import javafx.application.HostServices;
import javafx.application.Platform;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.control.TextField;
import javafx.scene.layout.*;
import javafx.scene.layout.*;
import javafx.stage.DirectoryChooser;
import javafx.stage.DirectoryChooser;
import org.json.JSONObject;
import org.json.JSONObject;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.javafx.FontIcon;
import java.awt.SystemTray;
import java.awt.SystemTray;
import java.io.BufferedReader;
import java.io.BufferedReader;
import java.io.File;
import java.io.File;
import java.io.InputStreamReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URL;
import java.util.logging.Logger;
import java.util.logging.Logger;
public class GeneralSettings extends VBox {
public class GeneralSettings extends VBox {
private final TextField serverNameTextField;
private final TextField serverNameTextField;
private final TextField portTextField;
private final TextField portTextField;
private final TextField pluginsPathTextField;
private final TextField pluginsPathTextField;
private final TextField themesPathTextField;
private final TextField themesPathTextField;
private final TextField actionGridPaneActionBoxSize;
private final TextField actionGridPaneActionBoxSize;
private final TextField actionGridPaneActionBoxGap;
private final TextField actionGridPaneActionBoxGap;
private final ToggleButton startOnBootToggleButton;
private final ToggleButton startOnBootToggleButton;
private final ToggleButton closeOnXToggleButton;
private final ToggleButton closeOnXToggleButton;
private final Button saveButton;
private final Button saveButton;
private final Button checkForUpdatesButton;
private final Button checkForUpdatesButton;
private Logger logger;
private Logger logger;
private ExceptionAndAlertHandler exceptionAndAlertHandler;
private ExceptionAndAlertHandler exceptionAndAlertHandler;
private ServerListener serverListener;
private ServerListener serverListener;
private HostServices hostServices;
private HostServices hostServices;
public GeneralSettings(ExceptionAndAlertHandler exceptionAndAlertHandler, ServerListener serverListener, HostServices hostServices)
public GeneralSettings(ExceptionAndAlertHandler exceptionAndAlertHandler, ServerListener serverListener, HostServices hostServices)
{
{
this.hostServices = hostServices;
this.hostServices = hostServices;
this.exceptionAndAlertHandler = exceptionAndAlertHandler;
this.exceptionAndAlertHandler = exceptionAndAlertHandler;
this.serverListener = serverListener;
this.serverListener = serverListener;
logger = Logger.getLogger(GeneralSettings.class.getName());
logger = Logger.getLogger(GeneralSettings.class.getName());
serverNameTextField = new TextField();
serverNameTextField = new TextField();
portTextField = new TextField();
portTextField = new TextField();
pluginsPathTextField = new TextField();
pluginsPathTextField = new TextField();
themesPathTextField = new TextField();
themesPathTextField = new TextField();
actionGridPaneActionBoxSize = new TextField();
actionGridPaneActionBoxSize = new TextField();
actionGridPaneActionBoxGap = new TextField();
actionGridPaneActionBoxGap = new TextField();
startOnBootToggleButton = new ToggleButton("Start on Boot");
startOnBootToggleButton = new ToggleButton("Start on Boot");
closeOnXToggleButton = new ToggleButton("Quit On window Close");
closeOnXToggleButton = new ToggleButton("Quit On window Close");
checkForUpdatesButton = new Button("Check for updates");
checkForUpdatesButton = new Button("Check for updates");
checkForUpdatesButton.setOnAction(event->checkForUpdates());
checkForUpdatesButton.setOnAction(event->checkForUpdates());
getStyleClass().add("general_settings");
getStyleClass().add("general_settings");
prefWidthProperty().bind(widthProperty());
prefWidthProperty().bind(widthProperty());
setAlignment(Pos.CENTER);
setAlignment(Pos.CENTER);
setSpacing(5);
setSpacing(5);
getChildren().addAll(
getChildren().addAll(
getUIInputBox("Server Name", serverNameTextField),
getUIInputBox("Server Name", serverNameTextField),
getUIInputBox("Port", portTextField),
getUIInputBox("Port", portTextField),
getUIInputBox("action Grid Pane action Box Size", actionGridPaneActionBoxSize),
getUIInputBox("Grid Pane - Box Size", actionGridPaneActionBoxSize),
getUIInputBox("action Grid Pane action Box Gap", actionGridPaneActionBoxGap),
getUIInputBox("Grid Pane - Box Gap", actionGridPaneActionBoxGap),
getUIInputBoxWithDirectoryChooser("Plugins Path", pluginsPathTextField),
getUIInputBoxWithDirectoryChooser("Plugins Path", pluginsPathTextField),
getUIInputBoxWithDirectoryChooser("Themes Path", themesPathTextField)
getUIInputBoxWithDirectoryChooser("Themes Path", themesPathTextField)
);
);
serverNameTextField.setPrefWidth(200);
serverNameTextField.setPrefWidth(200);
HBox toggleButtons = new HBox(closeOnXToggleButton, startOnBootToggleButton);
HBox toggleButtons = new HBox(closeOnXToggleButton, startOnBootToggleButton);
toggleButtons.setSpacing(10.0);
toggleButtons.setSpacing(10.0);
VBox.setMargin(toggleButtons, new Insets(30, 0 , 0,0));
VBox.setMargin(toggleButtons, new Insets(30, 0 , 0,0));
toggleButtons.setAlignment(Pos.CENTER);
toggleButtons.setAlignment(Pos.CENTER);
saveButton = new Button("Save");
saveButton = new Button("Save");
saveButton.setOnAction(event->save());
saveButton.setOnAction(event->save());
getChildren().addAll(toggleButtons, checkForUpdatesButton, saveButton);
getChildren().addAll(toggleButtons, checkForUpdatesButton, saveButton);
setPadding(new Insets(10));
setPadding(new Insets(10));
}
}
private HBox getUIInputBoxWithDirectoryChooser(String labelText, TextField textField)
private HBox getUIInputBoxWithDirectoryChooser(String labelText, TextField textField)
{
{
HBox hBox = getUIInputBox(labelText, textField);
HBox hBox = getUIInputBox(labelText, textField);
hBox.setSpacing(5.0);
hBox.setSpacing(5.0);
TextField tf = (TextField) hBox.getChildren().get(2);
TextField tf = (TextField) hBox.getChildren().get(2);
tf.setPrefWidth(300);
tf.setPrefWidth(300);
tf.setDisable(true);
tf.setDisable(true);
Button button = new Button();
Button button = new Button();
FontIcon fontIcon = new FontIcon("far-folder");
FontIcon fontIcon = new FontIcon("far-folder");
button.setGraphic(fontIcon);
button.setGraphic(fontIcon);
button.setOnAction(event -> {
button.setOnAction(event -> {
DirectoryChooser directoryChooser = new DirectoryChooser();
DirectoryChooser directoryChooser = new DirectoryChooser();
try {
try {
File selectedDirectory = directoryChooser.showDialog(getScene().getWindow());
File selectedDirectory = directoryChooser.showDialog(getScene().getWindow());
textField.setText(selectedDirectory.getAbsolutePath());
textField.setText(selectedDirectory.getAbsolutePath());
}
}
catch (NullPointerException e)
catch (NullPointerException e)
{
{
logger.info("No folder selected");
logger.info("No folder selected");
}
}
});
});
hBox.getChildren().add(button);
hBox.getChildren().add(button);
return hBox;
return hBox;
}
}
private HBox getUIInputBox(String labelText, TextField textField)
private HBox getUIInputBox(String labelText, TextField textField)
{
{
textField.setPrefWidth(100);
textField.setPrefWidth(100);
Label label = new Label(labelText);
Label label = new Label(labelText);
Region region = new Region();
Region region = new Region();
HBox.setHgrow(region, Priority.ALWAYS);
HBox.setHgrow(region, Priority.ALWAYS);
return new HBox(label, region, textField);
return new HBox(label, region, textField);
}
}
public void loadDataFromConfig() throws SevereException {
public void loadDataFromConfig() throws SevereException {
Config config = Config.getInstance();
Config config = Config.getInstance();
Platform.runLater(()->
Platform.runLater(()->
{
{
serverNameTextField.setText(config.getServerName());
serverNameTextField.setText(config.getServerName());
portTextField.setText(config.getPort()+"");
portTextField.setText(config.getPort()+"");
pluginsPathTextField.setText(config.getPluginsPath());
pluginsPathTextField.setText(config.getPluginsPath());
themesPathTextField.setText(config.getThemesPath());
themesPathTextField.setText(config.getThemesPath());
actionGridPaneActionBoxSize.setText(config.getActionGridActionSize()+"");
actionGridPaneActionBoxSize.setText(config.getActionGridActionSize()+"");
actionGridPaneActionBoxGap.setText(config.getActionGridActionGap()+"");
actionGridPaneActionBoxGap.setText(config.getActionGridActionGap()+"");
closeOnXToggleButton.setSelected(config.getCloseOnX());
closeOnXToggleButton.setSelected(config.getCloseOnX());
startOnBootToggleButton.setSelected(config.getStartOnBoot());
startOnBootToggleButton.setSelected(config.getStartOnBoot());
});
});
}
}
public void save()
public void save()
{
{
new Thread(new Task<Void>() {
new Thread(new Task<Void>() {
@Override
@Override
protected Void call()
protected Void call()
{
{
try {
try {
boolean toBeReloaded = false;
boolean toBeReloaded = false;
boolean dashToBeReRendered = false;
boolean dashToBeReRendered = false;
Platform.runLater(()->{
Platform.runLater(()->{
saveButton.setDisable(true);
saveButton.setDisable(true);
serverNameTextField.setDisable(true);
serverNameTextField.setDisable(true);
portTextField.setDisable(true);
portTextField.setDisable(true);
closeOnXToggleButton.setDisable(true);
closeOnXToggleButton.setDisable(true);
startOnBootToggleButton.setDisable(true);
startOnBootToggleButton.setDisable(true);
});
});
String serverNameStr = serverNameTextField.getText();
String serverNameStr = serverNameTextField.getText();
String serverPortStr = portTextField.getText();
String serverPortStr = portTextField.getText();
String pluginsPathStr = pluginsPathTextField.getText();
String pluginsPathStr = pluginsPathTextField.getText();
String themesPathStr = themesPathTextField.getText();
String themesPathStr = themesPathTextField.getText();
String actionGridActionBoxSize = actionGridPaneActionBoxSize.getText();
String actionGridActionBoxSize = actionGridPaneActionBoxSize.getText();
String actionGridActionBoxGap = actionGridPaneActionBoxGap.getText();
String actionGridActionBoxGap = actionGridPaneActionBoxGap.getText();
boolean closeOnX = closeOnXToggleButton.isSelected();
boolean closeOnX = closeOnXToggleButton.isSelected();
boolean startOnBoot = startOnBootToggleButton.isSelected();
boolean startOnBoot = startOnBootToggleButton.isSelected();
Config config = Config.getInstance();
Config config = Config.getInstance();
StringBuilder errors = new StringBuilder();
StringBuilder errors = new StringBuilder();
if(serverNameStr.isBlank())
if(serverNameStr.isBlank())
{
{
errors.append("* Server Name cannot be blank.\n");
errors.append("* Server Name cannot be blank.\n");
}
}
else
else
{
{
if(!config.getServerName().equals(serverNameStr))
if(!config.getServerName().equals(serverNameStr))
{
{
toBeReloaded = true;
toBeReloaded = true;
}
}
}
}
int serverPort=-1;
int serverPort=-1;
try {
try {
serverPort = Integer.parseInt(serverPortStr);
serverPort = Integer.parseInt(serverPortStr);
if (serverPort < 1024)
if (serverPort < 1024)
errors.append("* Server Port must be more than 1024");
errors.append("* Server Port must be more than 1024");
if(config.getPort()!=serverPort)
if(config.getPort()!=serverPort)
{
{
toBeReloaded = true;
toBeReloaded = true;
}
}
}
}
catch (NumberFormatException e)
catch (NumberFormatException e)
{
{
errors.append("* Server Port must be integer.\n");
errors.append("* Server Port must be integer.\n");
}
}
int actionSize=-1;
int actionSize=-1;
try {
try {
actionSize = Integer.parseInt(actionGridActionBoxSize);
actionSize = Integer.parseInt(actionGridActionBoxSize);
if(config.getActionGridActionSize() != actionSize)
if(config.getActionGridActionSize() != actionSize)
{
{
dashToBeReRendered = true;
dashToBeReRendered = true;
}
}
}
}
catch (NumberFormatException e)
catch (NumberFormatException e)
{
{
errors.append("* action Size must be integer.\n");
errors.append("* action Size must be integer.\n");
}
}
int actionGap=-1;
int actionGap=-1;
try {
try {
actionGap = Integer.parseInt(actionGridActionBoxGap);
actionGap = Integer.parseInt(actionGridActionBoxGap);
if(config.getActionGridActionGap() != actionGap)
if(config.getActionGridActionGap() != actionGap)
{
{
dashToBeReRendered = true;
dashToBeReRendered = true;
}
}
}
}
catch (NumberFormatException e)
catch (NumberFormatException e)
{
{
errors.append("* action Gap must be integer.\n");
errors.append("* action Gap must be integer.\n");
}
}
if(pluginsPathStr.isBlank())
if(pluginsPathStr.isBlank())
{
{
errors.append("* Plugins Path must not be blank.\n");
errors.append("* Plugins Path must not be blank.\n");
}
}
else
else
{
{
if(!config.getPluginsPath().equals(pluginsPathStr))
if(!config.getPluginsPath().equals(pluginsPathStr))
{
{
toBeReloaded = true;
toBeReloaded = true;
}
}
}
}
if(themesPathStr.isBlank())
if(themesPathStr.isBlank())
{
{
errors.append("* Themes Path must not be blank.\n");
errors.append("* Themes Path must not be blank.\n");
}
}
else
else
{
{
if(!config.getThemesPath().equals(themesPathStr))
if(!config.getThemesPath().equals(themesPathStr))
{
{
toBeReloaded = true;
toBeReloaded = true;
}
}
}
}
if(!errors.toString().isEmpty())
if(!errors.toString().isEmpty())
{
{
throw new MinorException("settings", "Please rectify the following errors and try again :\n"+errors.toString());
throw new MinorException("settings", "Please rectify the following errors and try again :\n"+errors.toString());
}
}
if(config.getStartOnBoot() != startOnBoot)
if(config.getStartOnBoot() != startOnBoot)
{
{
if(ServerInfo.getInstance().getRunnerFileName() == null)
if(ServerInfo.getInstance().getRunnerFileName() == null)
{
{
new StreamPiAlert("Uh Oh", "No Runner File Name Specified as startup arguments. Cant set run at boot.", StreamPiAlertType.ERROR).show();
new StreamPiAlert("Uh Oh", "No Runner File Name Specified as startup arguments. Cant set run at boot.", StreamPiAlertType.ERROR).show();
startOnBoot = false;
startOnBoot = false;
}
}
else
else
{
{
StartAtBoot startAtBoot = new StartAtBoot(SoftwareType.SERVER, ServerInfo.getInstance().getPlatformType());
StartAtBoot startAtBoot = new StartAtBoot(SoftwareType.SERVER, ServerInfo.getInstance().getPlatformType());
if(startOnBoot)
if(startOnBoot)
{
{
startAtBoot.create(new File(ServerInfo.getInstance().getRunnerFileName()));
startAtBoot.create(new File(ServerInfo.getInstance().getRunnerFileName()));
}
}
else
else
{
{
boolean result = startAtBoot.delete();
boolean result = startAtBoot.delete();
if(!result)
if(!result)
new StreamPiAlert("Uh Oh!", "Unable to delete starter file", StreamPiAlertType.ERROR).show();
new StreamPiAlert("Uh Oh!", "Unable to delete starter file", StreamPiAlertType.ERROR).show();
}
}
}
}
}
}
if(!closeOnX)
if(!closeOnX)
{
{
System.out.println("XYZ");
System.out.println("XYZ");
if(!SystemTray.isSupported())
if(!SystemTray.isSupported())
{
{
StreamPiAlert alert = new StreamPiAlert("Not Supported", "Tray System not supported on this platform ", StreamPiAlertType.ERROR);
StreamPiAlert alert = new StreamPiAlert("Not Supported", "Tray System not supported on this platform ", StreamPiAlertType.ERROR);
alert.show();
alert.show();
closeOnX = true;
closeOnX = true;
}
}
else
else
{
{
System.out.println("YES");
System.out.println("YES");
}
}
}
}
config.setServerName(serverNameStr);
config.setServerName(serverNameStr);
config.setServerPort(serverPort);
config.setServerPort(serverPort);
config.setActionGridGap(actionGap);
config.setActionGridGap(actionGap);
config.setActionGridSize(actionSize);
config.setActionGridSize(actionSize);
config.setPluginsPath(pluginsPathStr);
config.setPluginsPath(pluginsPathStr);
config.setThemesPath(themesPathStr);
config.setThemesPath(themesPathStr);
config.setCloseOnX(closeOnX);
config.setCloseOnX(closeOnX);
config.setStartupOnBoot(startOnBoot);
config.setStartupOnBoot(startOnBoot);
config.save();
config.save();
loadDataFromConfig();
loadDataFromConfig();
if(toBeReloaded)
if(toBeReloaded)
{
{
new StreamPiAlert("Restart","Restart to see changes", StreamPiAlertType.INFORMATION).show();
new StreamPiAlert("Restart","Restart to see changes", StreamPiAlertType.INFORMATION).show();
}
}
if(dashToBeReRendered)
if(dashToBeReRendered)
{
{
serverListener.clearTemp();
serverListener.clearTemp();
}
}
}
}
catch (MinorException e)
catch (MinorException e)
{
{
exceptionAndAlertHandler.handleMinorException(e);
exceptionAndAlertHandler.handleMinorException(e);
}
}
catch (SevereException e)
catch (SevereException e)
{
{
exceptionAndAlertHandler.handleSevereException(e);
exceptionAndAlertHandler.handleSevereException(e);
}
}
finally {
finally {
Platform.runLater(()->{
Platform.runLater(()->{
saveButton.setDisable(false);
saveButton.setDisable(false);
serverNameTextField.setDisable(false);
serverNameTextField.setDisable(false);
portTextField.setDisable(false);
portTextField.setDisable(false);
closeOnXToggleButton.setDisable(false);
closeOnXToggleButton.setDisable(false);
startOnBootToggleButton.setDisable(false);
startOnBootToggleButton.setDisable(false);
});
});
}
}
return null;
return null;
}
}
}).start();
}).start();
}
}
public void checkForUpdates()
public void checkForUpdates()
{
{
new Thread(new Task<Void>()
new Thread(new Task<Void>()
{
{
@Override
@Override
protected Void call() throws Exception {
protected Void call() throws Exception {
try
try
{
{
Platform.runLater(()->checkForUpdatesButton.setDisable(true));
Platform.runLater(()->checkForUpdatesButton.setDisable(true));
String jsonRaw = readUrl("https://stream-pi.com/API/get_latest.php?TYPE=SERVER");
String jsonRaw = readUrl("https://stream-pi.com/API/get_latest.php?TYPE=SERVER");
System.out.println(jsonRaw);
System.out.println(jsonRaw);
JSONObject jsonObject = new JSONObject(jsonRaw);
JSONObject jsonObject = new JSONObject(jsonRaw);
String latestVersionRaw = jsonObject.getString("Version");
String latestVersionRaw = jsonObject.getString("Version");
String releasePage = jsonObject.getString("Release Page");
String releasePage = jsonObject.getString("Release Page");
Version latestVersion = new Version(latestVersionRaw);
Version latestVersion = new Version(latestVersionRaw);
Version currentVersion = ServerInfo.getInstance().getVersion();
Version currentVersion = ServerInfo.getInstance().getVersion();
if(latestVersion.isBiggerThan(currentVersion))
if(latestVersion.isBiggerThan(currentVersion))
{
{
VBox vBox = new VBox();
VBox vBox = new VBox();
Hyperlink urlLabel = new Hyperlink(releasePage);
Hyperlink urlLabel = new Hyperlink(releasePage);
urlLabel.setOnAction(event->hostServices.showDocument(releasePage));
urlLabel.setOnAction(event->hostServices.showDocument(releasePage));
Label label = new Label(
Label label = new Label(
"New Version "+latestVersionRaw+" Available.\n" +
"New Version "+latestVersionRaw+" Available.\n" +
"Current Version "+currentVersion.getText()+".\n"+
"Current Version "+currentVersion.getText()+".\n"+
"Changelog and install instructions are included in the release page.\n" +
"Changelog and install instructions are included in the release page.\n" +
"It is recommended to update to ensure maximum stability and least bugs.");
"It is recommended to update to ensure maximum stability and least bugs.");
label.setWrapText(true);
label.setWrapText(true);
vBox.setSpacing(5);
vBox.setSpacing(5);
vBox.getChildren().addAll(
vBox.getChildren().addAll(
urlLabel,
urlLabel,
label
label
);
);
new StreamPiAlert("New Update Available!", StreamPiAlertType.INFORMATION, vBox).show();;
new StreamPiAlert("New Update Available!", StreamPiAlertType.INFORMATION, vBox).show();;
}
}
else
else
{
{
new StreamPiAlert("Up to Date", "Server is upto date. ("+currentVersion.getText()+")", StreamPiAlertType.INFORMATION).show();;
new StreamPiAlert("Up to Date", "Server is upto date. ("+currentVersion.getText()+")", StreamPiAlertType.INFORMATION).show();;
}
}
}
}
catch (Exception e)
catch (Exception e)
{
{
e.printStackTrace();
e.printStackTrace();
new StreamPiAlert("Uh Oh", "Update Check Failed. API Error/Network issue.", StreamPiAlertType.WARNING).show();;
new StreamPiAlert("Uh Oh", "Update Check Failed. API Error/Network issue.", StreamPiAlertType.WARNING).show();;
}
}
finally
finally
{
{
Platform.runLater(()->checkForUpdatesButton.setDisable(false));
Platform.runLater(()->checkForUpdatesButton.setDisable(false));
}
}
return null;
return null;
}
}
}).start();;
}).start();;
}
}
private String readUrl(String urlString) throws Exception {
private String readUrl(String urlString) throws Exception {
BufferedReader reader = null;
BufferedReader reader = null;
try {
try {
URL url = new URL(urlString);
URL url = new URL(urlString);
reader = new BufferedReader(new InputStreamReader(url.openStream()));
reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer buffer = new StringBuffer();
StringBuffer buffer = new StringBuffer();
int read;
int read;
char[] chars = new char[1024];
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
buffer.append(chars, 0, read);
return buffer.toString();
return buffer.toString();
} finally {
} finally {
if (reader != null)
if (reader != null)
reader.close();
reader.close();
}
}
}
}
}
}