EDIT: The problem was two-fold, first dictionary should be static and also i was using .contains() where i should have used .containsKey()
I'm trying to do a simple java client and server set up, this is what i have got and i can't seem to find anything wrong with the way i have done it but whenever i run the code i get the output:
Result = Added
Result = This word is not in the dictionary, please use the add function.
Which tells me that the server isn't storing the change made the the map when i am adding a word, is there something really simple i am missing here?
I can add anymore information needed if asked.
This is my client code:
public class Client {
#WebServiceRef(wsdlLocation =
"http://localhost:8080/P1Server/ServerService?wsdl")
public static void main(String[] args) {
try {
package1.ServerService service = new package1.ServerService();
package1.Server port = service.getServerPort();
String result = port.addWord("Test", "This is a test.");
System.out.println("Result = " + result);
result = port.getDefiniton("Test");
System.out.println("Result = " + result);
}catch(Exception ex)
{
System.out.println("Gone Wrong");
}
This is my relevant server code:
#WebService
public class Server {
private **static**ConcurrentHashMap<String,String> dictionary;
public Server() {
this.dictionary = new ConcurrentHashMap<>();
}
#WebMethod
public String addWord(String word, String definition){
if(dictionary.contains(word.toLowerCase())){
return "This word is already in the dictionary, "
+ "please use the update function.";
}else{
dictionary.put(word.toLowerCase(), definition);
return "Added";
}
}
#WebMethod
public String getDefiniton(String word){
if(dictionary.contains(word.toLowerCase())){
return dictionary.get(word);
}else{
return "This word is not in the dictionary, "
+ "please use the add function.";
}
}
Your problem has noting to with webservice.
Issue is with you logic
Modify your methods as follows :
public String addWord(String word, String definition) {
if (dictionary.containsKey(word.toLowerCase())) {
return "This word is already in the dictionary, "
+ "please use the update function.";
} else {
dictionary.put(word.toLowerCase(), definition);
return "Added";
}
}
public String getDefiniton(String word) {
if (dictionary.containsKey(word.toLowerCase())) {
return dictionary.get(word.toLowerCase());
} else {
return "This word is not in the dictionary, "
+ "please use the add function.";
}
}
It will work.
Hope this helps.
Web services are stateless by nature. Every web request will get its own contexts and instances. So, the instance of Server that served the port.addWord() request can be different than the one that served port.getDefinition(). In that case, the dictionary map that had the result placed into it is different than the one used to retrieve the results.
In order for this to work, the data needs to be persisted somehow on the Server side. This can be done via a database. Or, if you're just doing this for testing purposes, change the definition of dictionary to be static so that all instances of Server share the same map.
Define dictionary as static variable. So that every instance of Web service instances that get created in the server side will use same dictionary to put/get data.
private static ConcurrentHashMap<String,String> dictionary;
Related
I have a function that returns String.
private String processQuery(String[] args){
//code logic
}
Returned result can either be a answer (Your account detail is $account_detail.) or response (Sorry I cannot understand you?). Depending upon the result, code will do separate things.
What I came up with is to user Either<String, String>.
private Either<String,String> processQuery(String[] args){
//code logic
}
private void reply(String[] args){
//code logic
var either = processQuery(args);
return either.fold((l){
//returned result is answer
},(r){
//returned result is response
});
}
If it returns left then it is answer, if it returns right it is response. But since there is not Either type in java so I tried passing AtomicBoolean around.
What is the better solution for this only using java stl?
One solution is to make the method take two lambda functions that corresponds to a correct and an incorrect answer and then call only the appropriate one
private void processQuery(String[] args, Consumer<String> correct, Consumer<String> incorrect){
if (args.length == 0) {
incorrect.accept("Sorry I cannot understand you?");
return;
}
correct.accept("Your account detail is $account_detail.");
}
which can be called like this
private void reply(String[] args){
processQuery(args, (
reply -> System.out.println("Success!, " + reply)
),
(
reply -> System.out.println("Fail, " + reply)
)
);
}
or create variables for the different functions
Consumer<String> badAnswer = reply -> System.out.println("Fail, " + reply);
Consumer<String> goodAnswer = reply -> System.out.println("Success!, " + reply);
private void reply(String[] args){
processQuery(args, goodAnswer, badAnswer);
}
You can use Pair:
Pair<String, String> pair = Pair.with("Blah", "Blee");
See some example here
A better approach, if your responses actually represent some kind of an error, will be to throw an exception of some kind, and to keep the return value of String to represent a "good" flow.
is it possible to create a class and have a String ... attribute that takes as many or as little strings as you put?
example:
please excuse my rough pseudocode, this is for java.
//this is the method:
public void getXXXX(String ...) {
//random code executes in a loop with as many as strings that are inputted
}
//this code calls it
getXXXX("Benjamin","Jordan","Steve")
getXXXX("Pengu","No")
getXXXX("hi")
Yes, what you entered will more or less work, you just need a parameter name after your type.
class StringDecorator {
public static String join(final String... strings) {
final var builder = new StringBuilder();
for (final var string : strings) {
builder.append(string);
}
return builder.toString();
}
}
Then invoke this somewhere
StringDecorator.join("Hello, ", "World!"); // "Hello, World!"
Hello I'm testing the class that has some validating methods and I've been wondering if there is a way to reduce the duplicated code.
#Test
void testCorrectEmailValidator() {
List<String> correctEmails = Arrays.asList("test#test.com", "test123#test123.com", "test#test.com.in",
"test.test2#test.com", "test.test2.test3#test.com", "TEST.2test#test.com");
for (String email : correctEmails) {
boolean isValid = UserCredentialsValidator.emailValidator(email);
System.out.println("Email is valid: " + email + ": " + isValid);
assertTrue(isValid);
}
}
#Test
void testCorrectUsernameValidator() {
List<String> correctUsernames = Arrays.asList("username", "123username", "username3", "user2name",
"USERNAME", "USERNAME123", "123USERNAME123", "2uSERname33");
for(String username : correctUsernames) {
boolean isValid = UserCredentialsValidator.usernameValidation(username, userList);
System.out.println("Username is valid: " + username + " : " + isValid);
assertTrue(isValid);
}
}
I also have validators for other fields such as username etc. I was thinking about implementing a helper method that would accept: tested credential as String, List but I've got a problem with last parameter - a validating method, not sure how to pass that.
The code i would like to replace with some method is the for loop.
I am afraid your tests are of low quality.
The problems that should be fixed immediately include
UserCredentialsValidator.usernameValidation(username, userList); The method shouldn't take the second argument. The place from where that list is retrieved should be concealed from the API consumer.
List<String> correctEmails = Arrays.asList(...) and List<String> correctUsernames = Arrays.asList(...) should be removed. You'd better make the tests parameterised with #ParameterizedTest and #ValueSource.
I'd rather remove the System.out.println statements. They make little sense in tests.
#ParameterizedTest
#ValueSource(strings = {"test#test.com", "test123#test123.com"})
void testUserEmailValidationWithValidUserEmailShouldPass(String validUserEmail) {
boolean isValid = UserCredentialsValidator.emailValidator(validUserEmail);
assertTrue(isValid);
}
#ParameterizedTest
#ValueSource(strings = {"username", "123username"})
void testUserNameValidationWithValidUserNameShouldPass(String validUserName) {
boolean isValid = UserCredentialsValidator.usernameValidation(validUserName);
assertTrue(isValid);
}
Now there is nothing to reduce.
As I already stated in my comment to your question, I'm not sure rearranging your code would help much. However, as a comparision here's a Java8+ version which uses a common method:
#Test
void testCorrectEmailValidator() {
List<String> correctEmails = Arrays.asList("test#test.com", "test123#test123.com", "test#test.com.in",
"test.test2#test.com", "test.test2.test3#test.com", "TEST.2test#test.com");
testValidator( "Email", correctEmails , email -> UserCredentialsValidator.emailValidator(email) );
}
#Test
void testCorrectUsernameValidator() {
List<String> correctUsernames = Arrays.asList("username", "123username", "username3", "user2name",
"USERNAME", "USERNAME123", "123USERNAME123", "2uSERname33");
//I don't know where userList does come from but it would need to be final to be used here
testValidator( "Username", correctUsernames, username -> UserCredentialsValidator.usernameValidation(username, userList) );
}
void testValidator( String name, List<String> data, Predicate<String> validator) {
for( String element : data ) {
boolean isValid = validator.test( element );
System.out.println( name + " is valid: " + element + " : " + isValid);
assertTrue(isValid);
}
}
In that particular case both approaches would be 23 lines long while the second one might be easier to reuse but harder to understand and less flexible (e.g. if you'd need to pass additional parameters etc.)
Use parameterized tests:
static Stream<String> emailsSource() {
return Stream.of("test#test.com", "test123#test123.com", "test#test.com.in",
"test.test2#test.com", "test.test2.test3#test.com", "TEST.2test#test.com");
}
#Test
#MethodSource("emailsSource")
void testCorrectEmailValidator(String email) {
boolean isValid = UserCredentialsValidator.emailValidator(email);
assertTrue(isValid);
}
Repeat for usernameSource etc. IMHO, this is sufficient to eliminate duplicities.
However if you want to go further and generalize it, use method references. I wouldn't recommend it though.
static Stream<Pair<String,Predicate<String>>> allSources() {
return Stream.of(
Pair.of("test#test.com", UserCredentialsValidator::emailValidator),
Pair.of("username", UserCredentialsValidator::usernameValidationOneArg), // like usernameValidation but with argument userList fixed
...
);
}
#Test
#MethodSource("allSources")
void testAll(Pair<String,Predicate<String>> p) {
String s = p.getLeft();
Predicate<String> test = p.getRight();
boolean isValid = test.apply(email);
assertTrue(isValid);
}
Fact that you're struggling to test is indicating a design smell.
Its good time for you to explore strategy design pattern here.
Basically you main code would look something like
interface IValidator {
boolean isValid(List<String> yourDataToBeValidated);
}
Now create multiple validator classes for different fields like email, username etc.
class EmailValidator implements IValidator {
boolean isValid(List<String> yourDataToBeValidated){
//Email specific validations goes here
}
}
You can create more validators as you need on the go.
Now in your unit tests create new EmailValidator() or new UsernameValidator() and pass your emailIds or usernames to be isValid() method, something like below :
boolean isValid = new EmailValidator().isValid(Arrays.asList("test#test.com", "test123#test123.com");
assertTrue(isValid);
I know that the whole point of OOP is so that code doesnt have to be rewritten.
I have a class (lets call it E) and a main class (lets call it main) with a main method that validates some inputs and then feeds them into class E (which encrypts the inpts) to get a result to output to the user (the encrypted input).
Now I am writing a subclass from the perspective that I was someone else improving the program. I have a subclass of the encryption class which uses similar principles but an improved method of encryption (lets call it class ImprovedE).
As the new developer I am pretending to be, would I just write the subclass and then rewrite the main method from the original program to feed the inputs into Improved E instead of E?
I know I can't override the main method but I dont think I should be changing the original code either. Any help would be appreaciated.
Heres the code (EDIT), that i forgot to add.
package encryption;
import java.util.Scanner;
import static encryption.encryptionChoice.*;
public class main {
//These are all the reusable variables created to temporarily store information before pushing it to the Encryption class
//This is a simple starter message to inform the user of how to use the program
private String initialDisplayInformation = "Message Encryption/Decryption program for use with letters and spaces only. \nPress any key to continue...";
//These are the "scope" input and output variables visible to the user
private String inputString;
private String outputString;
//This creates the encryption class
private Encryption myEncryption = new Encryption();
//These are used to later create two loops that only break when an acceptable input has been input for the values
private Boolean inputValidated = false;
private Boolean cypherValidated = false;
private Boolean choiceValidated = false;
private void initialInfo() {
//These 2 lines make the user have to hit any key before continuing after reading the info
System.out.println(initialDisplayInformation);
String pressAnyKey = new Scanner(System.in).nextLine();
}
private void inputValidation(){
//This loop attepts to validate the message input and uses the boolean returned fromthe Encryption.setInput class to see the success
//It prints a detailed error and repeats if unsuccessful
do {
System.out.println("\nEnter your message: ");
try {
inputValidated = myEncryption.setInput(new Scanner(System.in).nextLine());
} catch(NotACharacterException e) {
System.out.println(e.errorMessage());
}
} while(!inputValidated);
}
private void cypherValidation(){
//This repeats the exact process as the previous loop, but for the cypher length
do {
System.out.println("\nEnter your cypher length (How much the message will be/was offset by: ");
try {
cypherValidated = myEncryption.setCypher(new Scanner(System.in).nextInt());
if(!cypherValidated) {
System.out.println("That is not an acceptable integer, please try again... ");
}
}catch(Exception e){
System.out.println("That is not a valid input, please try again... ");
}
} while(!cypherValidated);
}
private void encryptionDecision(){
do {
System.out.println("\nWould you like to 1)Encrypt 2)Decrypt the message: ");
String choiceString = new Scanner(System.in).nextLine();
encryptionChoice choice = ERROR;
if(choiceString.equalsIgnoreCase("Encrypt")|| choiceString.equalsIgnoreCase("1")){
choice = ENCRYPT;
}
if(choiceString.equalsIgnoreCase("Decrypt") || choiceString.equalsIgnoreCase("2")){
choice = DECRYPT;
}
try {
System.out.println(myEncryption.getInput());
System.out.println(myEncryption.EncryptionDecryption(choice));
choiceValidated = true;
} catch(IllegalArgumentException e) {
System.out.println("Please only enter: Encrypt, Decrypt, 1 or 2. Please try again... ");
}
} while(!choiceValidated);
}
public static void main(String[] args) {
boolean runProgram = true;
while(runProgram){
main thread = new main();
thread.initialInfo();
thread.inputValidation();
thread.cypherValidation();
thread.encryptionDecision();
runProgram=false;
Scanner keyboard = new Scanner(System.in);
System.out.println("\nPress 'r' to restart or 'enter' to exit");
if(new Scanner(System.in).nextLine().equals("r")) {
runProgram=true;
}
}
}
}
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package encryption;
/**
*
* #author Alex
*/
public class SingleKeywordEncryption extends Encryption {
protected String keywordString;
protected Integer getKeywordCypher(String keyword, Integer term){
Character letterInKeyword = 0;
Integer cypherLength;
if(term<keyword.length()){
letterInKeyword = keyword.charAt(term);
}
else if(term>=keyword.length()) {
letterInKeyword = keyword.charAt(term%keyword.length());
}
cypherLength = termOf(letterInKeyword);
return cypherLength;
}
#Override
public String EncryptionDecryption(encryptionChoice choice) {
String outputString = "";
switch(choice){
case ENCRYPT:
for(int i=0;i<inputString.length();i++) {
outputString = outputString + letterOf(termOf(inputString.charAt(i)) + getKeywordCypher(keywordString, i));
}
break;
case DECRYPT:
for(int i=0;i<inputString.length();i++) {
outputString = outputString + letterOf(termOf(inputString.charAt(i)) - getKeywordCypher(keywordString, i));
}
break;
default:
throw new IllegalArgumentException();
};
return outputString;
}
}
package encryption;//Includes the class int he encryption package of classes for my project
//This creates a class called Encryption where the majority of my project is stored
public class Encryption {
//These create the variables needed throughout the class
//This is final so that it is immutable and usable in all the methods
//I made it a Character array to save memory use and to allow simpler comparison methods in other areas of the program
private final Character[] alphabet = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
//These are private for good coding practice, so that they can only be modified from within the class
private Integer cypher;
protected String inputString;
public String getInput() {
return inputString;
}
//This class simply validates and saves the cypher length to its variable and returns a boolean of its success
public boolean setCypher(Integer cypherToAdd) {
while(cypherToAdd>26 || cypherToAdd<0){
return false;
}
//It tries to save it and returns false if it cannot be saved as an integer
try {
cypher = cypherToAdd;
}
catch (Exception e) {
return false;
}
return true;
}
//This class validates andsaves the input to its variable and removes any whitespace from it
public boolean setInput(String inputToAdd) throws NotACharacterException {
//This uses replaceAll to remove whitespace and saves the object that is rejurned from the method to String input
String input = inputToAdd.replaceAll("\\s","");
//This iterates through every character in the input and checks that it is a letter
for (int term=0; term<input.length();term++) {
//If a term is not a letter, it throws the custom NotACharacterException and passes information of which non-letter character caused it
if(!Character.isLetter(input.charAt(term))){
throw new NotACharacterException("'" + String.valueOf(input.charAt(term)) + "' This character can not be used in this program...\nStick to letters and spaces only please.");
}
}
inputString = input;
return true;
}
//This class returns the term of a passed letter in the alphabet
protected int termOf(Character letter) {
//The term variable to be returned is initialised immediately
int term =0;
//The for loop iterates through every letter in the alphabet and compares it with the letter passed to the method to find its term
for (int currentTerm=0; currentTerm<alphabet.length;currentTerm++) {
//When the letters match, the term is returned to where the method is called
if(letter.toLowerCase(letter)==alphabet[currentTerm]){
term = currentTerm;
}
}
return term;
}
//This class returns the letter of a passed term in the alphabet
protected Character letterOf(int inputTerm) {
if(inputTerm>25){
return alphabet[inputTerm-26];
} else if (inputTerm<0) {
return alphabet[inputTerm+26];
}
else {
//It recieves the character by gathering the character in the inputTerm's place in the array, and returns it
return alphabet[inputTerm];
}
}
public String EncryptionDecryption(encryptionChoice choice){
String outputString = "";
switch(choice){
case ENCRYPT:
for(int i=0;i<inputString.length();i++) {
outputString = outputString + letterOf(termOf(inputString.charAt(i))+ cypher);
}
break;
case DECRYPT:
for(int i=0;i<inputString.length();i++) {
outputString = outputString + letterOf(termOf(inputString.charAt(i))- cypher);
}
break;
default:
throw new IllegalArgumentException();
};
return outputString;
}
}
No matter what, you will have to change something somewhere in your code so that the main uses your ImprovedE class instead of the E class. Otherwise, the program will not know by itself if you want to use E or ImprovedE.
If you will not use the encryption method in E and will always use ImprovedE, it would be better to include all the methods from E into ImprovedE. This way, you will not have to make any decisions on which class to use.
If you still want to be able to switch between the two classes, I recommend using the Strategy design pattern. You would put any methods shared between the two classes (such as termOf(Character letter), letterOf(int inputTerm) and setInput(String inputToAdd)) in a class accessible by both encyption strategy, and you would have two ConcreteStrategy: E and ImprovedE.
This way, you can switch between the two strategies quickly, just by changing the ConcreteStrategy (In your case, if you want to use the old or the new encryption method). You could also prompt the user to know which encryption method he wants if that's a valid use case.
I know that the whole point of OOP is so that code doesnt have to be rewritten...
Actually, the purpose of OOP is to make the organization of code easier to conceptualize. extends is considered by many to be an antipattern.
Consider using implements on an abstract base class to define an interface and letting future devs worry about 'improvements'.
In Java, the main method is static, which means it cannot be overriden. This is by design, but not necessarily optimal design. There is no universal reason why this could not be done in principle, but Java does not do it.
The thing is: you should not have to need this in the first place. Your former developer mixed responsabilities by putting all of these encryption methods and state information in the same class which represents the computation itself: your main class.
So, what you have to do is actually decouple these things because the main method has to very small and narrow-purposed. When this happens, it will not feel like there is so much repetition in place. If there is, there is always more room for refactoring.
I am developing a standalone application to test a website using Selenium Webdriver. The application will use a JavaFX, or Swing, UI to allow a user to load a test suite file and select which tests to run and which browser to run them in. The UI will also capture data used by the tests, such as usernames and passwords.
I am planning on using JUnitCore to run the selected test classes but I will need to pass data from the UI to the test classes. For most of the data I can do this using System.setProperty(prop, value). However I will also need to pass admin, and other, passwords for the website to the tests
What would be the best way to pass the password(s) to the tests?
What would be the security concerns when using System.setProperty to store passwords? Should I instead encrypt the data and store it in a file and have the tests read the file and decrypt the data? This would obviously increase the amount of processing required to set up each test
If the user who runs the UI knows the passwords, then I don't really see your security concerns. Who are you defending from?
If the user who runs the UI does not know the passwords (and the passwords should be stored in the testcases themselves), then you're in a pickle - encrypting is good, but you have to store the password for decrypting somehow ... endless circle, there's no safe space. Even if the storing is safe, the weak points are definitely the transfer to browser (which will be done as plain string encapsulated in JSON no matter what) and the automated typing into the browser itself. Seriously, if you don't trust the machines the tests are run on, don't store the passwords.
However, for the first case (when the user has to type in the password into the UI), to minimize the possibility of threat and also for maximum convenience, I'd do this:
create a singleton class PasswordHolder
a PasswordHolder would remember the passwords (given to them by JPasswordField) in a Map<String, char[]> or Map<String, Password> where key is some password identifier and value is the password itself
once a password would be accessed via getPassword() method, it's contents would get nullified
A quick sample implementation (for further improvement as I hope I won't forget to include anything important ... but it could happen). I think it kinda speaks for itself:
public class PasswordHolder {
private static PasswordHolder instance = null;
private final Map<String, Password> map = new HashMap<String, Password>();
private PasswordHolder() {
// nothing to do
}
public static PasswordHolder getInstance() {
if (instance == null) {
instance = new PasswordHolder();
}
return instance;
}
public void addPassword(String name, char[] pass) {
if (map.containsKey(name)) {
// throw some sort of Exception("Duplicate password name, man.")
}
map.put(name, new Password(pass));
}
public Password getPassword(String name) {
return map.get(name);
}
}
As the most convenient thing, I wrote Password to be a CharSequence so is useful with sendKeys(CharSequence keys). Unfortunately, sendKeys() uses toString(), so you have to make a String out of the password anyway (which is considered a bad practice).
public class Password implements CharSequence {
private final char[] pass;
private final BitSet nulled;
Password(char[] pass) {
this.pass = pass;
nulled = new BitSet(pass.length);
}
private void nullify(int start, int end) {
for (int i = start; i < end; i++) {
pass[i] = '\0';
}
nulled.set(start, end);
}
#Override
public int length() {
return pass.length;
}
#Override
public char charAt(int index) {
if (nulled.get(index)) {
// throw some Exception("That character has already been read!")
}
char ret = pass[index];
pass[index] = '\0';
nulled.set(index);
return ret;
}
#Override
public CharSequence subSequence(int start, int end) {
if (nulled.get(start, end).cardinality() > 0) {
// throw some Exception("Some of the characters has already been read!")
}
Password subPass = new Password(Arrays.copyOfRange(pass, start, end));
nullify(start, end);
return subPass;
}
#Override
public String toString() {
if (nulled.cardinality() > 0) {
// throw some Exception("Some of the characters has already been read!")
}
String str = new String(pass);
nullify(0, pass.length);
return str;
}
}