In the below code I have two files. One is for my database connectivity and the other is for my html based jsp file. I am attempting to check the version of my database and print it to the screen. I am trying to return the value of CheckVersion and use out.println to put it on the webpage.
I am getting the follow errors.
type Exception report
message
descriptionThe server encountered an internal error () that prevented
it from fulfilling this request.
exception
org.apache.jasper.JasperException: PWC6033: Error in Javac compilation
for JSP
PWC6199: Generated servlet error: package
com.sun.xml.rpc.processor.modeler.j2ee.xml does not exist
PWC6199: Generated servlet error: package databaseFiles does not exist
PWC6197: An error occurred at line: 18 in the jsp file: /index.jsp
PWC6199: Generated servlet error: cannot find symbol symbol: class
DatabaseManagement location: class org.apache.jsp.index_jsp
PWC6197: An error occurred at line: 18 in the jsp file: /index.jsp
PWC6199: Generated servlet error: cannot find symbol symbol: class
DatabaseManagement location: class org.apache.jsp.index_jsp
What am I doing wrong? I am using netbeans and it is not reporting any problems with the way I created my file. index.jsp is in the root area and I created a folder named databaseFiles that is holding my DatabaseManagement.java file.
Thanks.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package databaseFiles;
import com.sun.corba.se.impl.util.Version;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author Aaron
*/
public class DatabaseManagement {
private final String urlDB = "jdbc:mysql://correct:3306/javaBBS";
private final String userDB = "correct";
private final String passwordDB = "correct";
Connection conDB = null;
Statement st = null;
ResultSet rs = null;
/*
*
*
*/
public DatabaseManagement() {
}
/*
*
*/
public void OpenConnection()
{
try {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch(Exception e) {
System.out.println("Could not load database driver");
}
conDB = DriverManager.getConnection(urlDB, userDB, passwordDB);
} catch(SQLException ex) {
Logger lgr = Logger.getLogger(Version.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
}
}
/*
* Closes the current database object
*/
public void CloseConnection() {
try {
if (rs != null) {
rs.close();
}
if (st != null) {
st.close();
}
if (conDB != null) {
conDB.close();
}
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Version.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
}
/**
* Checks the database version
*/
public String CheckVersion() throws SQLException {
try {
st = conDB.createStatement();
rs = st.executeQuery("SELECT VERSION()");
} catch(Exception e) {
System.out.println("Could not get the version of the DB.");
}
if (rs.next()) {
System.out.println(rs.getString(1));
}
return rs.getString(1);
}
}
The below is index.jsp.
<%--
Document : index
Created on : May 30, 2013, 1:48:03 PM
Author : Aaron
--%>
<%#page import="com.sun.xml.rpc.processor.modeler.j2ee.xml.string"%>
<%#page import="databaseFiles.DatabaseManagement"%>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Hello World!</h1>
<%
out.println("<br/>Your IP address is " + request.getRemoteAddr());
String userAgent = request.getHeader("user-agent");
String browser = "unknown";
out.print("<br/>and your browser is ");
if (userAgent != null) {
if (userAgent.indexOf("MSIE") > -1) {
browser = "MS Internet Explorer";
}
else if (userAgent.indexOf("Firefox") > -1) {
browser = "Mozilla Firefox";
}
else if (userAgent.indexOf("Opera") > -1) {
browser = "Opera";
}
else if (userAgent.indexOf("Chrome") > -1) {
browser = "Google Chrome";
}
else if (userAgent.indexOf("Safari") > -1) {
browser = "Apple Safari";
}
}
out.println(browser);
DatabaseManagement dbConnector = new DatabaseManagement();
dbConnector.OpenConnection();
out.println(dbConnector.CheckVersion());
dbConnector.CloseConnection();
%>
</body>
</html>
I think your project layout is the problem. It should be something like this:
root
WEB-INF
classes
databaseFiles
DatabaseManagement.class
index.jsp
So you should have your compiled .class files in the WEB-INF/classes directory and your .jsp files can go anywhere in the web application's root directory. Also, be sure that you're using the .class file and not the .java file.
Related
I can't able to store snapshot.data to database via floor in Flutter. I wrote entity, dao and database file, builded database and database.g.dart succesed to complete, but when I tried to insertUser function it turns below error;
What am I missing? Is there anything to do for record future snapshot.data which there isn't in [the guide]?1
Error:
════════ Exception caught by gesture ═══════════════════════════════════════════════════════════════
The following NoSuchMethodError was thrown while handling a gesture:
The method 'insertUser' was called on null.
Receiver: null
Tried calling: insertUser(Instance of 'UserF')
My entity:
import 'package:floor/floor.dart';
#entity
class UserF {
#PrimaryKey(autoGenerate: true)
final int id;
final String user;
final int overview;
UserF({this.id,
this.user,
this.overview,
#override
int get hashCode => id.hashCode ^ user.hashCode ^ overview.hashCode ;
#override
String toString() {
return 'UserF{id: $id, user: $user, overview: $overview}';
}
}
DAO:
import 'package:floor/floor.dart';
import 'entity.dart';
#dao
abstract class UserDao {
#Query('SELECT * FROM UserF')
Future<List<UserF>> findAllUsers();
#Query('SELECT * FROM UserF WHERE id = :id')
Stream<UserF> findUserById(int id);
#insert
Future<void> insertUser(UserF userF);
#delete
Future<int> deleteUser(UserF userF);
}
Database:
import 'dart:async';
import 'package:floor/floor.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
import 'user_dao.dart';
import 'entity.dart';
part 'database.g.dart'; // the generated code will be there
#Database(version: 1, entities: [UserF])
abstract class AppDatabase extends FloorDatabase {
UserDao get userDao;
}
Related Parts on my main.dart
Future<void> main() async{
WidgetsFlutterBinding.ensureInitialized();
final AppDatabase = await $FloorAppDatabase
.databaseBuilder('database.db')
.build();
runApp(MyApp());
}
....
floatingActionButton: FloatingActionButton(
onPressed: (){
final userf = UserF(user: snapshot.data.user, overview: snapshot.data.overview);
favoriteDao.insertUser(userf);
},
child: Icon(Icons.add),
....
If the code :
part 'database.g.dart';
is creating error that means you have to generate that file.
Add these dependencies if you haven't already:
Dependencies:
floor: ^0.14.0
sqflite: ^1.3.0
Dev Dependencies:
floor_generator: ^0.14.0
build_runner: ^1.8.1
In terminal run the following command:
flutter packages pub run build_runner build
And wait for some time. Flutter will generate the command.
Flutter will automatically generate the file.
REMEMBER: THE NAME OF THE DATABASE FILE AND NAME OF GENERATED FILE MUST BE SAME EXEPT FOR ADDING .g
For Example
if the database file name is mydatabase.dart
the generated file name must be mydatabase.g.dart
I want to download a file in Selenium web driver in C#.
i have the url in the web element as the attribute href. With that url, i have to download the file through javascript executor.
I tried with js executescript to get the file in the form of bytes and then converting it to pdf file and storing in my desired location. But no luck
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl("https://www.win-rar.com/predownload.html?&L=0");
string linkVal = driver.FindElement(By.LinkText("Download WinRAR")).GetAttribute("href");
var href = "https://www.win-rar.com/fileadmin/winrar-versions/winrar/winrar-x64-571.exe";
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
/// Object reposne = js.ExecuteScript("arguments[0].setAttribute(arguments[1],arguments[2])", linkVal, "href", "https://www.win-rar.com/postdownload.html?&L=0");
String script = "document.querySelector('a[href*=\"/print/\"]').setAttribute('download','name-of-the-download-file-recommend-guid-or-timestamp.pdf');";
///Object reposne = js.ExecuteAsyncScript(script , href);
var bytes = Convert.FromBase64String(reposne.ToString());
File.WriteAllBytes("F:\\file.exe", bytes);
I'm actually using RestSharp.
Like so:
public FileInfo DownloadFile(string downloadUrl)
{
RestClient rest = new RestClient();
RestRequest request = new RestRequest(downloadUrl);
byte[] downloadedfile = rest.DownloadData(request);
string tempFilePath = Path.GetTempFileName();
File.WriteAllBytes(tempFilePath, downloadedfile);
return new FileInfo(tempFilePath);
}
Consider not creating a rest client for each download request.
The RestClient also supports a base URL for convenience.
Hope this is what you wanted.
I have tested your scenario using Java, Selenium and TestNG. Where you can save the file in the root folder directory
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class FileDownload {
File folder;
WebDriver driver;
#SuppressWarnings("deprecation")
#BeforeMethod
public void setUp() {
//a random folder will be created 88998-98565-09792-783727-826233
folder = new File(UUID.randomUUID().toString());
folder.mkdir();
//Chrome Driver
System.setProperty("webdriver.chrome.driver", "---Your Chrome Driver or chromedriver.exe URL;--");
ChromeOptions options = new ChromeOptions();
Map<String, Object> prefs = new HashMap<String, Object>();
//When you click on download, it will ignore the popups
prefs.put("profile.default_content_settings.popups", 0);
prefs.put("download.default_directory", folder.getAbsolutePath());
options.setExperimentalOption("prefs", prefs);
DesiredCapabilities cap = DesiredCapabilities.chrome();
cap.setCapability(ChromeOptions.CAPABILITY, options);
driver = new ChromeDriver(cap);
}
#Test
public void downloadFileTest() throws InterruptedException{
driver.get("https://www.win-rar.com/predownload.html?&L=0");
driver.findElement(By.linkText("Download WinRAR")).click();
/* Depending on your download speed you have to increase or decrease the sleep value, if you give less than download time it will give error as: java.lang.AssertionError: expected [true] but found [false] */
Thread.sleep(5000);
File listOfFiles[] = folder.listFiles();
Assert.assertTrue(listOfFiles.length>0);
for(File file: listOfFiles){
Assert.assertTrue(file.length()>0);
}
}
#AfterMethod
public void tearDown() {
driver.quit();
/* You can comment below "for loop": for testing purpose where you can see the folder and file download, if you uncomment it will delete the file and folder: useful for regression you wont end up having so many files in the root folder */
for(File file: folder.listFiles()){
file.delete();
}
folder.delete();
}
}
If you are just trying to download the file, all you really need is this.
driver.FindElement(By.Id("download-button")).Click();
This will save it in your default location for your browser.
or in js executor
WebElement element = driver.findElement(By.id("download-button"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
To go to a specific location, try adding chrome options:
in C#
ChromeOptions options = new ChromeOptions();
options.AddArguments("--disable-extensions");
options.AddArguments("disable-infobars");
options.AddUserProfilePreference("download.default_directory", "My Path");
options.AddUserProfilePreference("profile.password_manager_enabled", false);
options.AddUserProfilePreference("credentials_enable_service", false);
_Driver = new ChromeDriver(#"DriverPath"), options);
_wait = new WebDriverWait(_webDriver, TimeSpan.FromSeconds(10));
_Driver.Manage().Window.Maximize();
as a last resort, just move the file with:
public class MoveMyFile
{
static void Main()
{
string sourceFile = #"C:\My\File\Path\file.txt";
string destinationFile = #"C:\My\New\Path\file.txt";
// Move my file to a new home!
System.IO.File.Move(sourceFile, destinationFile);
}
}
Updated
I tried to use the BrowserComponent on an Android device: if I touch the back button of the device, the app does nothing (with the following code).
In this question I copy the part of code that is relevant.
My question is if somebody can provide me an example of working code that executes a javascript function declared in the page when the back button is pressed (in particular, a function that goes to the previous page). Please take attention that I need the setBrowserNavigationCallback (as in the following code).
I also appreciate if somebody can correct the code to use the setURLHierarchy correctly, because it crashes the Simulator and it doesn't load "/community.html" on a real device.
Thank you very much for any help.
Update: this is the last version of my code
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Community", new BorderLayout());
// Suppress Android native indicator
Display.getInstance().setProperty("WebLoadingHidden", "true");
// Create the BrowserComponent
browser = new BrowserComponent();
// Set user-agent
browser.setProperty("useragent", appAgent);
// Set the start page - TO CORRECT, it's messy
if (Display.getInstance().isSimulator()) {
// I added this condition because opening a local html page
// causes that the Simulator crashes
browser.setURL(startPage_development);
Log.p("BrowserComponet setUrl: " + startPage_development);
} else {
try {
if (!Display.getInstance().isSimulator()) {
browser.setURLHierarchy("/community.html");
} else {
browser.setURLHierarchy("/testing.html");
}
Log.p("BrowserComponet setURLHierarchy successfully");
} catch (Exception err) {
Log.e(err);
browser.setURL(startPage);
Log.p("BrowserComponet setUrl: " + startPage);
}
}
// Javascript Bridge for back command
JavascriptContext context = new JavascriptContext(browser);
// JSObject document = (JSObject) context.get("document");
JSObject window = context.getWindow();
hi.setBackCommand(new Command("Back") {
#Override
public void actionPerformed(ActionEvent evt) {
//window.call("goBackButton()");
window.call("eval", new Object[]{"history.go(-1);"});
}
});
// Allow browsing only inside my domains
browser.setBrowserNavigationCallback((url) -> {
if (url.startsWith("javascript")
|| url.startsWith(url_Root_development)
|| url.startsWith(url_Root_production)
|| url.startsWith(loginRoot)) {
return true; // the BrowserComponent should navigate
} else {
Display.getInstance().callSerially(() -> {
// it opens the url with the native platform
Boolean can = Display.getInstance().canExecute(url);
if (can != null && can) {
Display.getInstance().execute(url);
}
});
return false; // the BrowserComponent shouldn't navigate
}
});
hi.add(BorderLayout.CENTER, browser);
hi.show();
}
Use setBackCommand to override the back button behavior and set up any business logic you might have including a call to JavaScript code.
I thanks Shai for the suggestions, but they weren't enough to get a working code and a working simulator (in which pressing escape does nothing, and I didn't understood the meaning of using a breakpoint in this case). Just invoke back() on the browser component isn't what I need, because I need to use a more complex approach, that is to invoke a javascript function written by me that makes the browser goes back only if the Internet connection is available yet (or it shows a message that Internet is not more available).
So, that's why I'm trying to answer the question by myself, decomposing the problem in several steps. I've spent several days and a lot of effort to solve a so simple problem (call a javascript pressing the back button), primarily because the lack of documentation (the Codename One JS Bridge package includes several examples in the API, but not this case) and the crashes (and strange behaviors) of the Codename One Simulator, as reported in the following text.
I hope to help other people sharing what I've done.
Step 1: Load a local page with the BrowserComponent
I created a new empty Codename One project with Netbeans, I gave it the name "myBrowser", package name "it.galgani.demos.mybrowser", main class name "MyBrowser", theme "native", template "Hello world (bare bones)".
I modified the default start() method so:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("MyBrowser", new BorderLayout());
// Create the BrowserComponent
BrowserComponent browser = new BrowserComponent();
try {
// Load a web page placed in the "html" package
browser.setURLHierarchy("/index.html");
Log.p("setURLHierarchy executed");
} catch (IOException ex) {
Log.e(ex);
}
hi.add(BorderLayout.CENTER, browser);
hi.show();
}
Then I created a new "Java package" inside the "Source packages" with the name "html". In my case, the created folder is: "/home/francesco/NetBeansProjects/myBrowser/src/html"
Inside the html folder, I created this index.html (selecting "New File", Category "Other", file type "HTML", file name "index"):
<!DOCTYPE html>
<html>
<head>
<title>BrowserComponent setURLHierarchy test</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div>Hello world</div>
</body>
</html>
Then I clicked on "Clean and Build Project" (no errors, it's good), then on "Run Project": it works, my "Hello world" is shown correctly. Now the next step...
Step 2: create other html pages
I modify the index.html so:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
Page 1<br />
Page 2<br />
Page 3<br />
</body>
</html>
and then I created page1.html, page2.html and page3.html with this code (changing the h1 according to the page):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>Page 1</h1>
</body>
</html>
I tried all in the simulator and it was ok. To go back from a page to the previous one, in the simulator there is an option accessible by clicking with the right button of the mouse on the page.
The log reported two java exception, the first one when the simulator is opened, the second one when it's closed, however they didn't influence the simulator functionality:
java.io.UTFDataFormatException: malformed input around byte 64
at java.io.DataInputStream.readUTF(DataInputStream.java:656)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at com.codename1.ui.util.Resources.loadTheme(Resources.java:1270)
at com.codename1.ui.util.Resources.openFileImpl(Resources.java:303)
at com.codename1.ui.util.Resources.openFile(Resources.java:269)
at com.codename1.ui.util.Resources.<init>(Resources.java:189)
at com.codename1.ui.util.Resources.open(Resources.java:768)
at com.codename1.ui.util.Resources.open(Resources.java:688)
at com.codename1.impl.javase.JavaSEPort$4.run(JavaSEPort.java:1720)
at com.codename1.ui.Display.processSerialCalls(Display.java:1056)
at com.codename1.ui.Display.mainEDTLoop(Display.java:873)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
[EDT] 0:0:1,396 - Codename One revisions: 14b404a993fcb91cfe25e26ce4d64ee044952b39
[EDT] 0:0:1,444 - setURLHierarchy executed
Exception in thread "JavaFX Application Thread" java.lang.IncompatibleClassChangeError
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
at java.lang.Thread.run(Thread.java:748)
The only true bad thing is that the text has a readable size using the iPhone3gs.skin, but it's very very small (quite unreadable) using other skins like SamsungS7.skin. I don't know why, I hope that the text will be correctly sized on real devices with a good-readable default font size.
Step 3: associate a command with the back button
In this case, to simplify and to test the back button, I didn't use the Javascript Bridge, but the back() method of the BrowserComponent class. I tried the Javascript Bridge in the next steps. I added at the end of the start() method of MyBrowser (just before hi.show()) this code:
hi.setBackCommand(new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
browser.back();
}
});
In the simulator, the hardware Back button is not reactive and no back arrow is shown in the toolbar. After several tries, I realized that the setBackCommand method is implemented in the Form class and in the Toolbar class, with different behaviors. This article explains the difference:
https://www.codenameone.com/blog/toolbar-back-easier-material-icons.html
The following was the final code of this step, that worked correctly in the simulator and in my real Android device (in which I tested both the hardware back button and the material icon back arrow):
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("MyBrowser", new BorderLayout());
// Create the BrowserComponent
BrowserComponent browser = new BrowserComponent();
try {
// Load a web page placed in the "html" package
browser.setURLHierarchy("/index.html");
Log.p("setURLHierarchy executed");
} catch (IOException ex) {
Log.e(ex);
}
hi.add(BorderLayout.CENTER, browser);
Command backCommand = new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
browser.back();
}
};
hi.getToolbar().setBackCommand(backCommand);
hi.show();
}
Step 4: use the Back Button with Javascript Bridge
I changed the backCommand as follow to call a simple writeln function, but the new code worked only few times, other times it crashed the simulator or it simply did nothing:
// Javascript Bridge
JavascriptContext context = new JavascriptContext(browser);
JSObject document = (JSObject)context.get("document");
Command backCommand = new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
// browser.back();
document.call("writeln", new Object[]{"Hello world"});
}
};
I have the suspect that the JavascriptContext is not loaded correctly all the times, but I'm not sure about that. The log wasn't helpful to understand the problem:
[EDT] 0:0:0,18 - setURLHierarchy executed
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f3a04f944d1, pid=3730, tid=0x00007f3a07cdf700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libjfxwebkit.so+0x11334d1] checkJSPeer(long, int, OpaqueJSValue*&, OpaqueJSContext const*&)+0x41
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/francesco/NetBeansProjects/myBrowser/hs_err_pid3730.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Java Result: 134
After a (very very long) list of trial and errors to solve this strange behavior, finally I changed the code in a way that works correctly in the simulator and in my real Android device (note that I didn't use anymore the JavascriptContext class):
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("MyBrowser", new BorderLayout());
// Create the BrowserComponent
BrowserComponent browser = new BrowserComponent();
try {
// Load a web page placed in the "html" package
browser.setURLHierarchy("/index.html");
Log.p("setURLHierarchy executed");
} catch (IOException ex) {
Log.e(ex);
}
hi.add(BorderLayout.CENTER, browser);
// Create a command for the Back button
Command backCommand = new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
browser.execute("document.writeln('Hello world!');");
}
};
hi.getToolbar().setBackCommand(backCommand);
hi.show();
}
The trick is the use of the (few documented) execute method of BrowserComponent, instead of the JavascriptContext + JSObject classes. A brief explanation of this method is inside the StackOverflow question: Clarification on Codename One's BrowserComponent execute(String javaScript) method.
Step 5: use my goBackButton() javascript function
I already had implemented the goBackButton() function in the web pages that I intend to use in my app. I want to call that method only if it's already loaded by the javascript engine, because: «BrowserComponent.execute(String) will execute the provide JS snippet in the current page of the browser at the time that you make the call. If your snippet references things that aren't loaded yet, then the javascript will result in an error.» (citation)
That's why I changed the code so:
// Create a command for the Back button
String jsCode = "function goBack() { "
+ " if (typeof goBackButton == 'function') { "
+ " window.goBackButton(); "
+ " return 'I\\'m invoking goBackButton()'; "
+ " } else { "
+ " window.history.go(-1); "
+ " return 'goBackButton() is not available';"
+ " } "
+ "} "
+ "goBack(); ";
Command backCommand = new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
Log.p(browser.executeAndReturnString(jsCode));
}
};
To do a basic test, I implemented a fake goBackButton() in page1.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
function goBackButton() {
// My js code
// ...
history.go(-1);
}
</script>
</head>
<body>
<h1>Page 1</h1>
</body>
</html>
Then I tapped the back button on page1.html and page2.html. The resulting log is as expected:
[EDT] 0:0:0,28 - setURLHierarchy executed
[EDT] 0:0:4,395 - I'm invoking goBackButton()
[EDT] 0:0:7,736 - goBackButton() is not available
Step 6: use setBrowserNavigationCallback
I used the setBrowserNavigationCallback to allow the browsing only inside my domains: in my original bugged code, I experienced that if I use JavascriptContext + JSObject classes then I have to use the condition if(url.startsWith("javascript")), because the NavigationCallback was called by tapping the back button (don't ask me why, I don't know). Instead using BrowserComponent.execute(String) I don't need to check if the url starts with "javascript", because the NavigationCallback is never called by javascript.
I added two links to index.html to do some checks:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
Page 1<br />
Page 2<br />
Page 3<br />
WebPage 1 (domain not allowed)<br />
WebPage2 (domain allowed)
</body>
</html>
The following code seems correct, but indeed it crashed the simulator every time that I clicked on the "WebPage 1" link (that is the Google page):
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("MyBrowser", new BorderLayout());
// Create the BrowserComponent
BrowserComponent browser = new BrowserComponent();
try {
// Load a web page placed in the "html" package
browser.setURLHierarchy("/index.html");
Log.p("setURLHierarchy executed");
} catch (IOException ex) {
Log.e(ex);
}
hi.add(BorderLayout.CENTER, browser);
// Create a command for the Back button
String jsCode = "function goBack() { "
+ " if (typeof goBackButton == 'function') { "
+ " window.goBackButton(); "
+ " return 'I\\'m invoking goBackButton()'; "
+ " } else { "
+ " window.history.go(-1); "
+ " return 'goBackButton() is not available';"
+ " } "
+ "} "
+ "goBack(); ";
Command backCommand = new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
Log.p(browser.executeAndReturnString(jsCode));
}
};
hi.getToolbar().setBackCommand(backCommand);
// Allow browsing only inside my domains
String myDomain1 = "127.0.0.1"; // for local server (using simulator)
String myDomain2 = "utiu-students.net";
String myDomain3 = "login.uninettunouniversity.net";
browser.setBrowserNavigationCallback((url) -> {
Log.p("URL loaded: " + url);
String domain = ""; // the domain of the url loaded by BrowserComponent
if (url.startsWith("http")) {
try {
domain = (new URI(url)).getHost();
domain = domain.startsWith("www.") ? domain.substring(4) : domain;
} catch (URISyntaxException ex) {
Log.e(ex);
}
}
Log.p("Domain of the URL: " + domain);
if (url.startsWith("file")
|| domain.equals(myDomain1)
|| domain.equals(myDomain2)
|| domain.equals(myDomain3)) {
Log.p("the BrowserComponent can navigate");
return true; // the BrowserComponent can navigate
} else {
Display.getInstance().callSerially(() -> {
// it opens the url with the native platform
Boolean can = Display.getInstance().canExecute(url);
if (can != null && can) {
Display.getInstance().execute(url);
}
});
Log.p("the BrowserComponent cannot navigate");
return false; // the BrowserComponent cannot navigate
}
});
hi.show();
}
This is the log:
[JavaFX Application Thread] 0:0:2,86 - URL loaded: https://www.google.com/
[JavaFX Application Thread] 0:0:2,87 - Domain of the URL: google.com
[JavaFX Application Thread] 0:0:2,88 - the BrowserComponent cannot navigate
[JavaFX Application Thread] 0:0:3,815 - URL loaded: https://www.google.it/?gfe_rd=cr&ei=avGmWa-YNKnS8AfqlIGoDw
[JavaFX Application Thread] 0:0:3,815 - Domain of the URL: google.it
[JavaFX Application Thread] 0:0:3,815 - the BrowserComponent cannot navigate
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f3ec48044cf, pid=5754, tid=0x00007f3ec7be4700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libjfxwebkit.so+0xa9e4cf] WebCore::ResourceLoader::willSendRequestInternal(WebCore::ResourceRequest&, WebCore::ResourceResponse const&)+0x53f
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/francesco/NetBeansProjects/myBrowser/hs_err_pid5754.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Java Result: 134
It's very bad. The strange thing is that the Google page was loaded two times, I guess because a redirect. If a replace the link to Google with a link to the Codename One website, the Simulator stops to crash... but it opens the page! So the BrowserNavigationCallBack() is not working.
I did two checks because this problem.
The first one was the support for the native browser:
// Check if the native browser is supported (only for logging)
if (BrowserComponent.isNativeBrowserSupported()) {
Log.p("Native Browser Supported");
} else {
Log.p("Native Browser NOT Supported");
}
The second one was removing the code of BrowserNavigationCallBack() and replacing it with:
browser.setBrowserNavigationCallback((new BrowserNavigationCallback() {
#Override
public boolean shouldNavigate(String url) {
Log.p("URL: " + url);
return false;
}
}));
The bad result was that the CodenameOne web site was still opened: the return value of shouldNavigate is ignored by the simulator (is it a bug?). This is the log:
[EDT] 0:0:0,44 - Native Browser Supported
[EDT] 0:0:0,59 - setURLHierarchy executed
[JavaFX Application Thread] 0:0:0,90 - URL: file:///home/francesco/NetBeansProjects/myBrowser/build/classes/html/index.html
[JavaFX Application Thread] 0:0:2,535 - URL: https://www.codenameone.com/
However, after several tries, I found a small workaround, that I suppose fine for the most use cases.
I added this code at the end of setBrowserNavigationCallback:
Log.p("the BrowserComponent cannot navigate");
if (Display.getInstance().isSimulator()) {
// small workaround because the return value is ignored by the simulator
browser.setURL("jar:///goback.html");
}
return false; // the BrowserComponent cannot navigate
I placed the goback.html outside the html package, in the /src:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>window.history.go(-1);</script>
</head>
<body>
The link will be opened with an external browser.<br />
Click here to go back
</body>
</html>
Now the simulator works (apparently) correctly: it seems to don't open a link to a not allowed domain... indeed it opens it for a very small while, then goes back automatically (and it opens it with an external browser, as I wanted).
There is also a very good news: do you remember that clicking the following link crashes the simulator (I reported the log above)? My workaround resolved also this issue: no crash, no strange behavior and the link is opened in an external browser.
WebPage 1 (domain not allowed)<br />
The app runs correctly also in my real Android device.
This is the final code:
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("MyBrowser", new BorderLayout());
// Create the BrowserComponent
BrowserComponent browser = new BrowserComponent();
// Check if the native browser is supported (only for logging)
if (BrowserComponent.isNativeBrowserSupported()) {
Log.p("Native Browser Supported");
} else {
Log.p("Native Browser NOT Supported");
}
try {
// Load a web page placed in the "html" package
browser.setURLHierarchy("/index.html");
Log.p("setURLHierarchy executed");
} catch (IOException ex) {
Log.e(ex);
}
hi.add(BorderLayout.CENTER, browser);
// Create a command for the Back button
String jsCode = "function goBack() { "
+ " if (typeof goBackButton == 'function') { "
+ " window.goBackButton(); "
+ " return 'I\\'m invoking goBackButton()'; "
+ " } else { "
+ " window.history.go(-1); "
+ " return 'goBackButton() is not available';"
+ " } "
+ "} "
+ "goBack(); ";
Command backCommand = new Command("BackButton") {
#Override
public void actionPerformed(ActionEvent evt) {
Log.p(browser.executeAndReturnString(jsCode));
}
};
hi.getToolbar().setBackCommand(backCommand);
// Allow browsing only inside my domains
String myDomain1 = "127.0.0.1"; // for local server (using simulator)
String myDomain2 = "utiu-students.net";
String myDomain3 = "login.uninettunouniversity.net";
browser.setBrowserNavigationCallback((url) -> {
Log.p("URL loaded: " + url);
String domain = ""; // the domain of the url loaded by BrowserComponent
if (url.startsWith("http")) {
try {
domain = (new URI(url)).getHost();
domain = domain.startsWith("www.") ? domain.substring(4) : domain;
} catch (URISyntaxException ex) {
Log.e(ex);
}
}
Log.p("Domain of the URL: " + domain);
if (url.startsWith("file")
|| domain.equals(myDomain1)
|| domain.equals(myDomain2)
|| domain.equals(myDomain3)) {
Log.p("the BrowserComponent can navigate");
return true; // the BrowserComponent can navigate
} else {
Display.getInstance().callSerially(() -> {
// it opens the url with the native platform
Boolean can = Display.getInstance().canExecute(url);
if (can != null && can) {
Display.getInstance().execute(url);
}
});
Log.p("the BrowserComponent cannot navigate");
if (Display.getInstance().isSimulator()) {
// small workaround because the return value is ignored by the simulator
browser.setURL("jar:///goback.html");
}
return false; // the BrowserComponent cannot navigate
}
}
);
hi.show();
}
For reference, the final full source code of this (very small) browsing app is here:
https://github.com/jsfan3/CodenameOne-Apps/tree/master/Browsing/myBrowser
Step 7: test the app with the real web content
Now it's the time to test the app with real content. I removed the files in the html packages and copied the ones that I want to use. Result: my javascript code doesn't run as expected in the simulator (maybe because the JavaFX limits), however the app initially works fine, as expected, in my real Android device. Then, after several minutes, the hardware back button stopped to work and the material left arrow icon disappeared... it's very frustrating, killing the app and rebooting the phone didn't restore the back button: I had to remove and to reinstall the app to get it working again (I'll investigate this issue in another episode, at the moment I'm not able to replicate it...).
I would like to externalise my selenium tests setting in order to make them more configurable.
I would like to externalise my testURL and my node URLS.
Here is my code :
public void setup () throws MalformedURLException
{ //the URL of the application to be tested
TestURL = "http://frstmwarwebsrv2.orsyptst.com:9000";
//Hub URL
BaseURL = "http://10.2.128.126";
//Node1 URL
winURL = "http://10.2.128.120:5556/wd/hub";
//Node2 URL
androidURL ="http://10.2.128.120:5555/wd/hub";
At the moment I have added this setup function in every test I would like to have it in an XML file for an example in order to make it configurable, any suggestions?
Thanks
Thanks for your help
Update :
Here is what i did so far :
Added a config.properties file with this content :
# This is my test.properties file
AppURL = http://************
HubURL= http://*****************
WinURL= http://*********/wd/hub
AndroidURL =
iOSURL
And created a classe to read properties :
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
public class ReadPropertiesFile {
public static void main(String[] args) {
try {
File file = new File("config.properties");
FileInputStream fileInput = new FileInputStream(file);
Properties properties = new Properties();
properties.load(fileInput);
fileInput.close();
Enumeration enuKeys = properties.keys();
while (enuKeys.hasMoreElements()) {
String key = (String) enuKeys.nextElement();
String value = properties.getProperty(key);
System.out.println(key + ": " + value);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
when running this i get this error :
java.io.FileNotFoundException: config.properties (The system cannot find the file specified)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at ReadPropertiesFile.main(ReadPropertiesFile.java:15)
my properties file is under src folder
Two basic ways you could do this are:
Pass in JVM argument and access it using System.getProperty(...)
Externalize your configuration in to properties files, like here
I recently implemented the second one in my Selenium tests and can expand this answer to give more details if you need them.
In my tests, I resolved it that I created Java class called Environment to store information about given Environment:
Few snippets of code:
public enum NameOfEnvironment {
SYSTEMTEST, ACCEPTANCE
}
stores the Name of given Environment :)
public String getBaseUrl() {
switch (actualEnvironment) {
case SYSTEMTEST: {
baseUrl = getPrefix() + "172.23.32.251:9092/pages/index.html";
break;
}
will return me the URL to the environment. And on beginning of the test I have something like this:
public static final Environment USED_ENVIRONMENT = new Environment(Environment.NameOfEnvironment.SYSTEMTEST);
And later on I just call USED_ENVIRONMENT.getBaseUrl() which will return me the link which is being actual for current run
Btw, to fill in the blanks, here is the constructor f the class
public Environment(NameOfEnvironment env) {
this.actualEnvironment = env;
}
I cannot get any automation working with Appium vs the Safari mobile browser on an iOS emulator. In my Java project, Safari will launch, but the browser will not even navigate to the specified website. Can anyone tell me what I'm doing wrong with my code?
1) Launch the Appium application on my OSX machine. It is configured with the following settings:
IP Address: 127.0.0.1
Port: 4723
Force Device: Checked - iPhone
User Mobile Safari: Checked
(Note: No messages scroll across the Appium application log screen when I run my project. Previously, I got complaints about a missing iOS 6.0 library, but when I duplicated the 6.1 iOS library and then renamed the directory to 6.0, the messages went away.)
2) Launch Eclipse and open Appium Project
3) Right-click on test code and click RunAs Junit
4) The iPhone emulator launches -- iPhone iOS 6.1
5) Mobile Safari launches...and then goes nowhere (should be going to cnn.com). I get no errors.
Can Appium Java projects actually be used for mobile-Safari automation? I don't see any examples of Safari automation in the Appium sample code repo.
What gives?
Thanks,
Larry
------------------Java code below----------------------------------------
Eclipse Juno is being used to run my Java/Appium project. Here is a much simplified listing of the Java JUnit project code (which, when modified accordingly, and used with iWebDriver and the deprecated iPhoneDriver(), works fine):
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
public class AppiumiPhoneWebDriverDemo {
private String baseUrl;
private WebDriver driver;
#Before
public void setup() throws Exception
{
WebDriver driver;
DesiredCapabilities cap = new DesiredCapabilities();
//cap.setCapability("", "");
//cap.setCapability("browsername", "");
//cap.setCapability("os", "iOS 6.1");
cap.setCapability("device", "iPhone Simulator");
cap.setCapability("app", "safari");
driver = new RemoteWebDriver(new URL("http://localhost:4723/wd/hub"), cap);
baseUrl = "http://www.cnn.com";
}
#After
public void tearDown() throws Exception
{
driver.quit();
}
#Test
public void test_searchWorks() throws Exception
{
this.driver.get(baseUrl);
driver.quit();
}
}
You can definitely do this.
See this code
"use strict";
require("./helpers/setup");
var wd = require("wd"),
_ = require('underscore'),
serverConfigs = require('./helpers/appium-servers');
describe("ios safari", function () {
this.timeout(300000);
var driver;
var allPassed = true;
before(function () {
var serverConfig = process.env.SAUCE ?
serverConfigs.sauce : serverConfigs.local;
driver = wd.promiseChainRemote(serverConfig);
require("./helpers/logging").configure(driver);
var desired = _.clone(require("./helpers/caps").ios81);
desired.browserName = 'safari';
if (process.env.SAUCE) {
desired.name = 'ios - safari';
desired.tags = ['sample'];
}
return driver.init(desired);
});
after(function () {
return driver
.quit()
.finally(function () {
if (process.env.SAUCE) {
return driver.sauceJobStatus(allPassed);
}
});
});
afterEach(function () {
allPassed = allPassed && this.currentTest.state === 'passed';
});
it("should get the url", function () {
return driver
.get('https://www.google.com')
.sleep(1000)
.waitForElementByName('q', 5000)
.sendKeys('sauce labs')
.sendKeys(wd.SPECIAL_KEYS.Return)
.sleep(1000)
.title().should.eventually.include('sauce labs');
});
it("should delete cookie passing domain and path", function () {
var complexCookieDelete = function(name, path, domain) {
return function() {
path = path || '|';
return driver.setCookie({name: name, value: '', path: path,
domain: domain, expiry: 0});
};
};
return driver
.get('http://en.wikipedia.org')
.waitForElementByCss('.mediawiki', 5000)
.allCookies() // 'GeoIP' cookie is there
.deleteCookie('GeoIP')
.allCookies() // 'GeoIP' is still there, because it is set on
// the .wikipedia.org domain
.then(complexCookieDelete('GeoIP', '/', '.wikipedia.org'))
.allCookies() // now 'GeoIP' cookie is gone
.sleep(1000);
});
});
Why do you define a second WebDriver in your setUp method ? Remove this second definition to set up the class member driver.
DesiredCapabilities cap = new DesiredCapabilities();
//cap.setCapability("", "");
//cap.setCapability("browsername", "");
//cap.setCapability("os", "iOS 6.1");
cap.setCapability("device", "iPhone Simulator");
cap.setCapability("app", "safari");
should be
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability("deviceName", "iPhone Simulator");
cap.setCapability("browsername", "safari");
cap.setCapability("platformVersion", "7.1");
cap.setCapability("platformName", "iOS");
It works for me. hope it fix your issue. Good luck.
Assuming you're using Java on Mac, here's something which works for me, including the code to start Appium Service itself, then the driver to connect to it:
package baseTest;
import com.groupon.tests.mainapp.pages.*;
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class AppiumSafariBaseUITest {
private WebDriver wd;
protected WebDriver getDriver(){
return wd;
}
String nodePath = "/Applications/Appium.app/Contents/Resources/node/bin/node";
String appiumJSPath = "/usr/local/lib/node_modules/appium/build/lib/main.js";
AppiumDriverLocalService service;
String service_url;
private void startAppiumServer() throws IOException {
service = AppiumDriverLocalService.buildService(new AppiumServiceBuilder()
.usingPort(4890)
.usingDriverExecutable(new File(nodePath))
.withAppiumJS(new File(appiumJSPath))
);
service.start();
}
#BeforeClass(alwaysRun = true)
public void setUpAppiumDriver() throws IOException {
startAppiumServer();
service_url = service.getUrl().toString();
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("appium-version", "1.0");
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "9.3");
capabilities.setCapability("deviceName", "iPhone 5s");
capabilities.setCapability("newCommandTimeout", 600);
capabilities.setCapability("bundleId", "com.apple.mobilesafari");
capabilities.setCapability("useLocationServices", false);
wd = new IOSDriver(new URL(service_url), capabilities);
}
#BeforeMethod(alwaysRun = true)
public void beforeMethod(){
if(!service.isRunning())
{
service.start();
}
}
#AfterClass(alwaysRun = true)
public void killSimulatorAndAppium(){
service.stop();
}
}