Issue
I'm currently experimenting with javafx and I'm trying to make a web browser with it. So far it's coming along pretty nicely, but it annoys me that I continuously have to log in on every single page. So I decided to use cookies and store them inside a file, so I don't have to log in each and every time. I've been trying to get this working for the past 5 hours, but I still have to log in each time. This is what I have so far:
public class Main extends Application {
public static void main(String[] args) {
if (!Values.SRCFILE.exists()) {
Installation.launch(Installation.class, args);
return;
}
launch(args);
}
private Stage stage;
private GridPane pane;
private List<BrowserTab> tabs;
@FXML
private TabPane tabPane;
@FXML
public void initialize() {
tabs = new ArrayList<>();
CookieManager manager = new CookieManager();
manager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
Map<String, List<String>> map = new HashMap<>();
URI uri = null;
try {
for (String line : Files.readAllLines(Values.COOKIESFILE.toPath())) {
String[] values = line.split("\\|");
URI newUri = new URI(values[0]);
if (uri == null)
uri = newUri;
if (!uri.equals(newUri)) {
CookieHandler.getDefault().put(uri, map);
uri = newUri;
System.out.println(map);
map = new HashMap<>();
}
String[] actualValues = values[1].split(":");
map.put(actualValues[0], Arrays.asList(actualValues[1].split(";")));
}
if (uri != null)
CookieHandler.getDefault().put(uri, map);
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
System.out.println(map);
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
if (tabs.size() > 1) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Closing window");
alert.setHeaderText("");
alert.setContentText("Are you sure you want to close this window? Doing so will close all open tabs");
alert.showAndWait();
}
//save cookies
CookieStore store = ((CookieManager) CookieHandler.getDefault()).getCookieStore();
try {
Files.write(Values.COOKIESFILE.toPath(), ("").getBytes(), StandardOpenOption.TRUNCATE_EXISTING);
for (URI uri : store.getURIs()) {
Map<String, List<String>> map = CookieHandler.getDefault().get(uri, new HashMap<>());
Files.write(Values.COOKIESFILE.toPath(), (uri + "|").getBytes(), StandardOpenOption.APPEND);
for (String value : map.keySet()) {
Files.write(Values.COOKIESFILE.toPath(), (value + ":").getBytes(), StandardOpenOption.APPEND);
for (String line : map.get(value))
Files.write(Values.COOKIESFILE.toPath(), (line + ";").getBytes(), StandardOpenOption.APPEND);
Files.write(Values.COOKIESFILE.toPath(), ("\n").getBytes(), StandardOpenOption.APPEND);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
addTab();
}
@Override
public void start(Stage primaryStage) {
this.stage = primaryStage;
stage.setTitle("Browser");
try {
// Load person overview.
FXMLLoader loader = new FXMLLoader();
loader.setController(this);
loader.setLocation(Main.class.getResource("/browser.fxml"));
pane = loader.load();
Scene scene = new Scene(pane);
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setURL(String url) {
tabs.get(tabPane.getSelectionModel().getSelectedIndex()).setURL(url);
}
public void search(String text) {
tabs.get(tabPane.getSelectionModel().getSelectedIndex()).search(text);
}
void addTab() {
BrowserTab browserTab = new BrowserTab(this);
browserTab.setText("Loading...");
browserTab.setURL("https://google.com/");
tabs.add(browserTab);
browserTab.setOnClosed(new EventHandler<Event>() {
@Override
public void handle(Event event) {
tabs.remove(browserTab);
if (tabPane.getTabs().isEmpty())
Platform.exit();
}
});
tabPane.getTabs().add(browserTab);
}
And my BrowserTab class
public class BrowserTab extends Tab {
private Main main;
private GridPane pane;
@FXML
private WebView webView;
@FXML
private TextField urlField;
@FXML
private Button backButton;
@FXML
private Button forwardButton;
@FXML
private Button goButton;
@FXML
private Button addTabButton;
public BrowserTab(Main main) {
this.main = main;
try {
FXMLLoader loader = new FXMLLoader();
loader.setController(this);
loader.setLocation(getClass().getResource("/tab-template.fxml"));
setContent(loader.load());
} catch (IOException e) {
e.printStackTrace();
}
initialize();
}
@FXML
public void initialize() {
webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
@Override
public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
if (newState == Worker.State.SUCCEEDED) {
String title = webView.getEngine().titleProperty().getValue();
if (title == null || title.trim().isEmpty())
title = webView.getEngine().getLocation();
setText(title);
urlField.setText(webView.getEngine().getLocation());
}
}
});
backButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
WebHistory history = webView.getEngine().getHistory();
history.go(-1);
int index = history.getCurrentIndex();
if (index + 1 > history.getEntries().size() - 1)
forwardButton.setDisable(true);
else
forwardButton.setDisable(false);
if (index - 1 < 0)
backButton.setDisable(true);
else
backButton.setDisable(false);
}
});
forwardButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
WebHistory history = webView.getEngine().getHistory();
history.go(1);
int index = history.getCurrentIndex();
if (index + 1 > history.getEntries().size() - 1)
forwardButton.setDisable(true);
else
forwardButton.setDisable(false);
if (index - 1 < 0)
backButton.setDisable(true);
else
backButton.setDisable(false);
}
});
urlField.setOnKeyPressed(new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ENTER)
goButton.fire();
}
});
goButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
String url = urlField.getText();
if (!url.contains(".")) {
search(url);
return;
}
if (!(url.startsWith("http://") || url.startsWith("https://")))
url = "http://" + url;
setURL(url);
}
});
webView.getEngine().getHistory().getEntries().addListener(new ListChangeListener<WebHistory.Entry>() {
@Override
public void onChanged(Change<? extends WebHistory.Entry> c) {
Platform.runLater(new Runnable() {
@Override
public void run() {
int index = webView.getEngine().getHistory().getCurrentIndex();
System.out.println(index);
if (index + 1 > c.getList().size() - 1)
forwardButton.setDisable(true);
else
forwardButton.setDisable(false);
if (index - 1 < 0)
backButton.setDisable(true);
else
backButton.setDisable(false);
}
});
}
});
addTabButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
addTab();
}
});
}
public void setURL(String url) {
webView.getEngine().load(url);
}
public void search(String text) {
webView.getEngine().load("https://google.com/search?q=" + text);
}
private void addTab() {
main.addTab();
}
The file formatting looks like this:
uri1|value:string1;string2;string3;
uri2|value:string1;string2;string3;
Any help would really be appreciated.
Solution
Alright after some more digging I found the solution.
The problem is that the default string inside the map (key element) is always 'Cookie:'. However, when creating the map to actually add it to the CookieHandler it should be either 'Set-Cookie' or 'Set-Cookie2'. If it isn't either one of these, it'll simply skip the value and you end up with no cookies at all. Also, I ended up using a CookieManager and some methods to turn cookies into strings and vice versa. When creating the CookieManager you have to be careful to choose the constructor with two parameters (cookiestore and cookiepolicy) and not the one with zero parameters. Choosing the one with zero paramaters will not create a cookiestore and result in an error. When using the one with two parameters, just leave the store as null and it will create one for you. This is what I ended up using:
Saving:
CookieStore store = ((CookieManager) CookieHandler.getDefault()).getCookieStore();
try {
Files.write(Values.COOKIESFILE.toPath(), ("").getBytes(), StandardOpenOption.TRUNCATE_EXISTING);
for (URI uri : store.getURIs()) {
Map<String, List<String>> map = CookieHandler.getDefault().get(uri, new HashMap<>());
Files.write(Values.COOKIESFILE.toPath(), (uri + "|Cookie:").getBytes(), StandardOpenOption.APPEND);
for (HttpCookie cookie : store.get(uri)) {
if (cookie.hasExpired())
continue;
Files.write(Values.COOKIESFILE.toPath(), (CookieUtil.toString(cookie) + "~").getBytes(), StandardOpenOption.APPEND);
}
Files.write(Values.COOKIESFILE.toPath(), "\n".getBytes(), StandardOpenOption.APPEND);
}
} catch (IOException e) {
e.printStackTrace();
}
Loading:
CookieManager manager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
try {
for (String line : Files.readAllLines(Values.COOKIESFILE.toPath())) {
String[] values = line.split("\\|");
URI uri = new URI(values[0]);
String[] actualValues = values[1].split(":");
if (actualValues.length < 2)
continue;
for (String header : actualValues[1].split("~"))
manager.getCookieStore().add(uri, CookieUtil.fromString(header));
}
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
CookieHandler.setDefault(manager);
Answered By - user5910225
Answer Checked By - Mildred Charles (JavaFixing Admin)