I'm new to JAVA, but I know Objective-C. I have to write a server side Custom Code and I'm having trouble with the code below:
/**
* This example will show a user how to write a custom code method
* with two parameters that updates the specified object in their schema
* when given a unique ID and a `year` field on which to update.
*/
public class UpdateObject implements CustomCodeMethod {
#Override
public String getMethodName() {
return "CRUD_Update";
}
#Override
public List<String> getParams() {
return Arrays.asList("car_ID","year");
}
#Override
public ResponseToProcess execute(ProcessedAPIRequest request, SDKServiceProvider serviceProvider) {
String carID = "";
String year = "";
LoggerService logger = serviceProvider.getLoggerService(UpdateObject.class);
logger.debug(request.getBody());
Map<String, String> errMap = new HashMap<String, String>();
/* The following try/catch block shows how to properly fetch parameters for PUT/POST operations
* from the JSON request body
*/
JSONParser parser = new JSONParser();
try {
Object obj = parser.parse(request.getBody());
JSONObject jsonObject = (JSONObject) obj;
// Fetch the values passed in by the user from the body of JSON
carID = (String) jsonObject.get("car_ID");
year = (String) jsonObject.get("year");
//Q1: This is assigning the values to fields in the fetched Object?
} catch (ParseException pe) {
logger.error(pe.getMessage(), pe);
return Util.badRequestResponse(errMap, pe.getMessage());
}
if (Util.hasNulls(year, carID)){
return Util.badRequestResponse(errMap);
}
//Q2: Is this creating a new HashMap? If so, why is there a need?
Map<String, SMValue> feedback = new HashMap<String, SMValue>();
//Q3: This is taking the key "updated year" and assigning a value (year)? Why?
feedback.put("updated year", new SMInt(Long.parseLong(year)));
DataService ds = serviceProvider.getDataService();
List<SMUpdate> update = new ArrayList<SMUpdate>();
/* Create the changes in the form of an Update that you'd like to apply to the object
* In this case I want to make changes to year by overriding existing values with user input
*/
update.add(new SMSet("year", new SMInt(Long.parseLong(year))));
SMObject result;
try {
// Remember that the primary key in this car schema is `car_id`
//Q4: If the Object is updated earlier with update.add... What is the code below doing?
result = ds.updateObject("car", new SMString(carID), update);
//Q5: What's the need for the code below?
feedback.put("updated object", result);
} catch (InvalidSchemaException ise) {
return Util.internalErrorResponse("invalid_schema", ise, errMap); // http 500 - internal server error
} catch (DatastoreException dse) {
return Util.internalErrorResponse("datastore_exception", dse, errMap); // http 500 - internal server error
}
return new ResponseToProcess(HttpURLConnection.HTTP_OK, feedback);
}
}
Q1: Code below is assigning the values to fields in the fetched Object?
carID = (String) jsonObject.get("car_ID");
year = (String) jsonObject.get("year");
Q2: Is this creating a new HashMap? If so, why is there a need?
Map<String, SMValue> feedback = new HashMap<String, SMValue>();
Q3: This is taking the key "updated year" and assigning a value (year)? Why?
feedback.put("updated year", new SMInt(Long.parseLong(year)));
Q4: If the Object is updated earlier with update.add... What is the code below doing?
result = ds.updateObject("car", new SMString(carID), update);
Q5: What's the code below doing?
feedback.put("updated object", result);
Original Code
SMSet
SMInt
Q1: They read from the fetched JSON object and stores the values of the fields car_ID and year in two local variables with the same names.
Q2: Yes. The feedback seems to be a map that will be sent back to the client as JSON
Q3: It stores the value read into the local variable 'year' (as described earlier) in the newly created hashmap 'feedback'
Q4: Not sure, I assume the ds object is some sort of database. If so it looks like it takes the updated values stored in the hashmap 'update' and pushes it to the database.
Q5: It stores the "result" object under the key "updated object" in the feedback hashmap.
Hope this helps :)
Q1
No, it does not appear to be setting a class member variable, but rather a variable local to the execute() method. As soon as the method returns, those local vars are cleaned up by the GC. Well, not really, but they are now subject to GC, but that's getting really technical.
Q2
Yes, you are creating a HashMap and putting it's reference into a Map. Map is an interface, and it's good practice in Java to reference thing like this. This way you are not tying your code to a specific implementation. I believe in Objective-C they are know as Prototypes???
Q3
I am not sure why they are doing this. I assume somewhere in the code the feedback Map is used, and that value is plucked back out. Think of Maps as an NSDictionary. It looks like "year" is a String, so they use Long.parseLong() to convert it. Not sure what SMInt is...from the name it looks like a custom class that represents a "small int"???
Q4
I don't know what DataService is, but I have to guess its some sort of service the reads/write data??? From the method, I am guessing its calling the service to update the values you just changed.
Q5
Again, feedback is a Map...it's putting result in the "updated object" key of that map.
Related
I'm writing a simple skill similart to the java airplane facts sample and I have two strange behaviours:
1) the same code in one intent works correctly, but in another causes an error;
2) I can't remove an element from a public static List!
I will try to explain better with a very close example.
I have two Intents that we can call:
- ActionIntent;
- StopIntent.
The first intent retrieves a list (of type List) retrieved from a class Constants and returns an attribute of a random CustomObject --
this works correctly.
Then it should set the object to Session Attributes and remove it from the list, because the next time the response should be a second attribute of the last CustomObject plus the first attribute of the new CustomObject. Does it make sense?
Here is the code:
// this row works correctly on the other intent
Map<String, Object> sessionAttributes = input.getAttributesManager().getSessionAttributes();
CustomObject last=(sessionAttributes.get("last")!=null) ? (CustomObject)sessionAttributes.get("last") : null;
List<CustomObject> allObjects = MAPPER.convertValue(Constants.getAllObjects(), List.class);
int index = new Random().nextInt(tutti.size());
CustomObject new = allObjects.get(index);
// a simple method that contains allObjects.remove(index) because it didn't work here but also this cause an error
Constants.removeCustomObjectFromList(index);
sessionAttributes.put("ultimoNome", nuovoNome);
String title = Constants.SKILL_TITLE;
String primaryText =new.getTrue();
String secondaryText =(last!=null) ?last.getFalse() : "";
String speechText = "" + secondaryText + " "+primaryText + "?";
return input.getResponseBuilder()
.withSpeech(speechText)
.withSimpleCard(title, primaryText)
.withReprompt(speechText)
.build();
If I comment out the rows linked to the sessionAttribute and the Constants.removeCustomObjectFromList it works correctly but, as I said, the reference to sessionAttribute works correctly in another intent and I must remove CustomObjects from my initial list because the user should listen two time the same thing!
Could someone tell me where to find good info on this subject?
https://ask-sdk-for-nodejs.readthedocs.io/en/latest/Managing-Attributes.html
Above is the official docs. It can be a bit difficult to understand a couple things in there due to lack of extensive explanation, but for the most part everything you need is there. As for your issue, I don't know if this is the only cause, but I don't think getAttributesManager() is a function, unless that's something you've defined. Your code:
Map<String, Object> sessionAttributes = input.getAttributesManager().getSessionAttributes();
Can you try:
Map<String, Object> sessionAttributes = input.attributesManager.getSessionAttributes();
instead?
I am having a problem with passing of variables between classes.
The problem that I am having is that the second class is not obtaining the variable data from the third class after first class sets the value to teh variables in third class.
The way in which I would like it to work is that I have one class (classA) where it obtains the value from the user and calls the set method is the third class to set the value to the variable, second class (classB) will be used get the value using the get method in the third class and the third class (ClassC) is where get and set methods resides.
ClassA method coding:
//method for 'add' button functionality
public void btnAddActionPerformed(java.awt.event.ActionEvent evt)
{
ArrayList<UserInfo> userobjList = new ArrayList<>();
//calling data field revelant text fields
int EmpNumber = Integer.parseInt(txtEmpNum.getText());
String EmpAccessType = txtAccessType.getText();
//creating the object to parse data to userinfo class
UserInfo user = new UserInfo(EmpNumber, EmpAccessType);
//setting the data to varibales in userinfo class
user.setEmpNumber(EmpNumber);
user.setEmpAccessType(EmpAccessType);
//adds the object to the arraylist
userobjList.add(user);
//creates the object to use the method for adding employee to system
AddEmpFunction addUser = new AddEmpFunction();
addUser.test();
}
This class obtains user information and sets the data in the third class
ClassB method for adding user to system coding:
//variables
int EmpNumber;
String AccessTypes;
//creation of object to be used throughout
UserInfo user = new UserInfo(EmpNumber, AccessTypes);
public void AddNewEmpLogin()
{
try
{
//SQL string command to be executed to add user login details
String addNewUserLogin = "insert into userLoginData(Username, accessType) values ("
+ user.getEmpNum() + ","
+ quotate(user.getEmpAccessType()) + ")";
//create the statement that will be used
Statement stmt=conn.createStatement();
//executes the addNewUser statement
stmt.executeUpdate(addNewUserLogin);
}
catch (Exception e)
{
//exception error message is shown
JOptionPane.showMessageDialog(null, "Error adding new User's details \n " + e, "Database Error", JOptionPane.ERROR_MESSAGE);
}
}
This class is where the data will be obtained from third class and then stored in MySQL.
ClassC is where the get and set methods are:
private int EmpNumber;
private String EmpAccessType;
//constructor
public UserInfo(int EmpNumber, String EmpAccessType)
{
this.EmpNumber = EmpNumber;
this.EmpAccessType = EmpAccessType;
}
public int getEmpNum()
{
return EmpNumber;
}
public void setEmpNum(int EmpNum)
{
this.EmpNumber = EmpNum;
}
public String getEmpAccessType()
{
return EmpAccessType;
}
public void setEmpAccessType(String EmpAccessType)
{
this.EmpAccessType = EmpAccessType;
}
The data is passing perfectly well from classA to classC but the data returned in classB whcih calls it up form classC displays null for the string and 0 for the integer.
Please could someone please explain where my problem is and how I can fix this. I have read a lot about get and set methods and there is no actualy example for what I am trying to achieve.
Any help will be much appreciated. :)
Because you have two different instances of the third class. You're doing this in one place (variable names changed to illustrate):
UserInfo userA = new UserInfo();
userA.setEmpNumber(EmpNumber);
userA.setEmpAccessType(EmpAccessType);
And then this in another:
UserInfo userB = new UserInfo();
userB.getEmpNumber();
userB.getEmpAccessType();
So you set data on one object, and then try to get that data from another object. But you can't, because no data was ever set on that object.
As an analogy, consider two identical cars. Same make, same model, came off the same production line. You are putting gas into one car, then trying to drive the other one. But you can't. Because it doesn't have any gas in it.
You need to use the same instance of the object:
UserInfo user = new UserInfo();
user.setEmpNumber(EmpNumber);
user.setEmpAccessType(EmpAccessType);
// ...
user.getEmpNumber();
user.getEmpAccessType();
If your second class needs a valid instance of your third class in order to perform its task, then it should require that as a constructor parameter. So when the first class holds that user variable and then creates an instance of the second class, it passes the user variable to that instance. So there's only one user.
(Additionally, as a side note, you don't need to pass the values to the constructor and use the setters. One or the other is fine. A value only needs to be set once.)
int EmpNumber;
String AccessTypes;
//creation of object to be used throughout
UserInfo user = new UserInfo(EmpNumber, AccessTypes);
You set up new user with no field filled.
And then you
+ user.getEmpNum() + ","
+ quotate(user.getEmpAccessType()) + ")";
from your empty user so it returns 0 and null respectively.
Pass your user from classA to classB first?
Your class B does not seem to receive data from class A.
Class C, UserInfo is a data store object (POJO) but the instance user that is created in class A is never passed to class B in your sample code.
As a matter of fact, class B seems to create its own instance of UserInfo with empty values.
So, to keep this short: pass the user object from class A to B, for example by using AddEmpLogin( UserInfo user ).
Next, read a solid introduction to object-oriented programming.
While implementing a database structure, my goal is to provide easy access to player data.
So, I have created the User class, which holds a Json instance and exposes the methods to take specific information from it.
public class User {
private Json data;
public User(OfflinePlayer player) {
File path = new File(player.getUniqueId() + ".json");
data = new Json(path);
}
public boolean isPremium() {
return data.getBoolean("premium");
}
}
The problem is that I have to create a new instance every time I need to know something about the same player from different parts of my code. That's very expensive!
So, is there a design pattern for this particular situation?
This is a simple cache. If you are using ORM such as hibernate, you could use second level cache for this.
You could also have unique user identifier (UUID id) as a key, with user data as a value in Map.
So, when you get request for user data, you first see if you have user with this uuid in cache(Map) and return data if you do.
If you don't have it, then go in database and fetch data.
Try creating a Map like this:
User user = null;
Map<UUID, User> usermap = new HashMap<>;
//before creating new user instance check if its present in Map
if(usermap.containskey(id){
//get user from Map
user = usermap.get(id);
else{
//not in map so create new User
user = new User(id);
usermap.put(id,user);
}
//use user object
But please be careful to destroy usermap instance or object containing it once it is not required. You can also so several modification with limiting size etc.
EDIT: FML! MY implementation of hashcode had a lowercase c. -.-
I've been trying to learn TDD and have been following the 'By Example' book by Kent Beck; it's very good!
However, I can't seem progress because a value is returning null when I access a hashtable. I've run a debug session and the object with the value is clearly there yet the result is null.
The code to build and access is:
public void addRate(String from, String to, int rate){
this.rates.put(new Pair(from, to), new Integer(rate));
}
from and to are "GBP" and "USD". Also verified by debug.
Test case calling the above:
#Test
public void testreduceMoneyDifferentCurrency(){
Bank bank = new Bank();
bank.addRate("GBP", "USD", 2);
Money result = bank.reduce(Money.gbpound(2), "USD");
assertEquals(Money.dollar(1), result);
}
The reduce method in bank calls the method rate:
public Money reduce(Bank bank, String to){
int rate = bank.rate(this.currency, to);
return new Money(this.amount / rate, to);
}
Which is where the issue is:
public int rate(String from, String to){
if (from.equals(to)) return 1;
Integer rate = (Integer) this.rates.get(new Pair(from, to));
return rate.intValue();
}
The first line copes with USD -> USD conversions etc.
The Pair object is 2 strings built to be used as a key.
I've not used has tables a great deal but I can't see what the issue is, I know for certain that the values are in the hashtable but 'rate' is always returning a null value.
I can't see the wood for the trees. :) Could someone point me in the right direction please?
I think the problem is in the Pair method.
When you do this:
this.rates.get(new Pair(from, to));
you are creating a new instance of Pair, which is not the same as the one you've put into the map in the addRate method.
If you want the code to work correctly, you either have to use the same instance of Pair class or correctly implement equals and hashCode method on Pair class.
Here's a bit deeper insight into the inner working on HashMap and what you have to do to make it work: https://stackoverflow.com/a/6493946/2266098
Java keeps the reference of objects. So when you are trying to do this
this.rates.get(new Pair(from, to));
you are basically creating a new instance of Pair which does not exists as a key in your HashMap.
I'm trying to make sure my Jersey request parameters are sanitized.
When processing a Jersey GET request, do I need to filter non String types?
For example, if the parameter submitted is an integer are both option 1 (getIntData) and option 2 (getStringData) hacker safe? What about a JSON PUT request, is my ESAPI implementation enough, or do I need to validate each data parameter after it is mapped? Could it be validated before it is mapped?
Jersey Rest Example Class:
public class RestExample {
//Option 1 Submit data as an Integer
//Jersey throws an internal server error if the type is not Integer
//Is that a valid way to validate the data?
//Integer Data, not filtered
#Path("/data/int/{data}/")
#GET
#Produces(MediaType.TEXT_HTML)
public Response getIntData(#PathParam("data") Integer data){
return Response.ok("You entered:" + data).build();
}
//Option 2 Submit data as a String, then validate it and cast it to an Integer
//String Data, filtered
#Path("/data/string/{data}/")
#GET
#Produces(MediaType.TEXT_HTML)
public Response getStringData(#PathParam("data") String data) {
data = ESAPI.encoder().canonicalize(data);
if (ESAPI.validator().isValidInteger("data", data, 0, 999999, false))
{
int intData = Integer.parseInt(data);
return Response.ok("You entered:" + intData).build();
}
return Response.status(404).entity("404 Not Found").build();
}
//JSON data, HTML encoded
#Path("/post/{requestid}")
#POST
#Consumes({MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON})
#Produces(MediaType.TEXT_HTML)
public Response postData(String json) {
json = ESAPI.encoder().canonicalize(json);
json = ESAPI.encoder().encodeForHTML(json);
//Is there a way to iterate through each JSON KeyValue and filter here?
ObjectMapper mapper = new ObjectMapper();
DataMap dm = new DataMap();
try {
dm = mapper.readValue(json, DataMap.class);
} catch (Exception e) {
e.printStackTrace();
}
//Do we need to validate each DataMap object value and is there a dynamic way to do it?
if (ESAPI.validator().isValidInput("strData", dm.strData, "HTTPParameterValue", 25, false, true))
{
//Is Integer validation needed or will the thrown exception be good enough?
return Response.ok("You entered:" + dm.strData + " and " + dm.intData).build();
}
return Response.status(404).entity("404 Not Found").build();
}
}
Data Map Class:
public class DataMap {
public DataMap(){}
String strData;
Integer intData;
}
The short answer is yes, though by "filter" I interpret it as "validate," because no amount of "filtering" will EVER provide you with SAFE data. You can still run into integer overflows in Java, and while those may not have immediate security concerns, they could still put parts of your application in an unplanned for state, and hacking is all about perturbing the system in ways you can control.
You packed waaaaay too many questions into one "question," but here we go:
First off, the lines
json = ESAPI.encoder().canonicalize(json);
json = ESAPI.encoder().encodeForHTML(json);
Aren't doing what you think they're doing. If your JSON is coming in as a raw String right here, these two calls are going to be applying mass rules across the entire string, when you really need to handle these with more surgical precision, which you seem to at least be subconsciously aware of in the next question.
//Is there a way to iterate through each JSON KeyValue and filter
here?
Partial duplicate of this question.
While you're in the loop discussed here, you can perform any data transformations you want, but what you should really be considering is using the JSONObject class referenced in that first link. Then you'll have JSON parsed into an object where you'll have better access to JSON key/value pairs.
//Do we need to validate each DataMap object value and is there a
dynamic way to do it?
Yes, we validate everything that comes from a user. All users are assumed to be trained hackers, and smarter than you. However if you handled filtering before you do your data mapping transformation, you don't need to do it a second time. Doing it dynamically?
Something like:
JSONObject json = new JSONObject(s);
Iterator iterator = json.keys();
while( iterator.hasNext() ){
String data = iterator.next();
//filter and or business logic
}
^^That syntax is skipping typechecks but it should get you where you need to go.
/Is Integer validation needed or will the thrown exception be good
enough?
I don't see where you're throwing an exception with these lines of code:
if (ESAPI.validator().isValidInput("strData", dm.strData, "HTTPParameterValue", 25, false, true))
{
//Is Integer validation needed or will the thrown exception be good enough?
return Response.ok("You entered:" + dm.strData + " and " + dm.intData).build();
}
Firstly, in java we have autoboxing which means this:
int foo = 555555;
String bar = "";
//the code
foo + bar;
Will be cast to a string in any instance. The compiler will promote the int to an Integer and then silently call the Integer.toString() method. Also, in your Response.ok( String ); call, THIS is where you're going to want to encodeForHTML or whatever the output context may be. Encoding methods are ALWAYS For outputting data to user, whereas canonicalize you want to call when receiving data. Finally, in this segment of code we also have an error where you're assuming that you're dealing with an HTTPParameter. NOT at this point in the code. You'll validate http Parameters in instances where you're calling request.getParameter("id"): where id isn't a large blob of data like an entire JSON response or an entire XML response. At this point you should be validating for things like "SafeString"
Usually there are parsing libraries in Java that can at least get you to the level of Java objects, but on the validation side you're always going to be running through every item and punting whatever might be malicious.
As a final note, while coding, keep these principles in mind your code will be cleaner and your thought process much more focused:
user input is NEVER safe. (Yes, even if you've run it through an XSS filter.)
Use validate and canonicalize methods whenever RECEIVING data, and encode methods whenever transferring data to a different context, where context is defined as "Html field. Http attribute. Javascript input, etc...)
Instead of using the method isValidInput() I'd suggest using getValidInput() because it will call canonicalize for you, making you have to provide one less call.
Encode ANY time your data is going to be passed to another dynamic language, like SQL, groovy, Perl, or javascript.