Click to See Complete Forum and Search --> : error counter help


jrthor2
09-14-2004, 01:59 PM
I need to write a class file that can be re-usable throughout our application. What I need to do is create a class file that when a user enters in some data, and that data is validated against our database, if the data is invalid (wrong pw, invalid userid, etc), my class creates a cookie that is just a counter and implents by one each time the user gets an error, and once the user gets 3 errors, they are redirected to a customer service page. We are using J2EE and using IBM's WebSphere.

Thanks for any help!!!

ray326
09-14-2004, 02:15 PM
Create a little error counter object in their Session. All it needs to be is a bean incapsulating an int like so:

public ErrorCounter
{
private int errorCount = 0;

ErrorCounter ErrorCounter()
{
super();
}

int getErrorCount()
{
return errorCount;
}

void countUp()
{
errorCount++;
}
}

That's probably got errors but it'd be a trivial class to build in WSAD anyway. If you're completely new to Java and J2EE then I sure hope you've got a mentor there or plenty of training budget.

OBTW, I hope your example was just that. You should not be doing your own user validation in J2EE; there are standard ways of leaving that job to the container.

jrthor2
09-14-2004, 02:21 PM
We are lookig at container manages security. How would I do this using that instead of this way?

Also, in your code example, how do I redirect accordingly?

buntine
09-14-2004, 08:20 PM
You could implement a static instance method, which will return the current state of the object to any class in the application.

public ErrorCounter
{
public ErrorCounter()
{
count = 0;
instance = this;
}

public static ErrorCounter getInstance()
{
return instance;
}

public int getErrorCount()
{
return count;
}

public void addError()
{
count++;
}

private int count;
private static ErrorCounter instance;
}

You could easily pass exception data to the addError method.

After the class has been created, you will be able to get it from anywhere by using the following code.

ErrorCounter counter = ErrorCounter.getInstance();

Regards.

ray326
09-14-2004, 11:08 PM
Originally posted by jrthor2
We are lookig at container manages security. How would I do this using that instead of this way?

Also, in your code example, how do I redirect accordingly? The security stuff is way too much to be explained in a forum like this. I'd recommend you get cozy with the WAS Infocenter and the IBM Redbooks site.

That bean is just a little counter. What you do when you notice its value is above your threshold of pain is sort of open ended. If you declare it with a useBean tag on a JSP and check it with a scriptlet then you can do a redirect right there (as long as the headers aren't already commited).

jrthor2
09-15-2004, 07:34 AM
buntine,

I was thinking of being able to use an import statement at the top of our pages to import this code so the page can use it. Is that how I would do it with your code? Make it a package and import it in the page?

Thanks for all the help

buntine
09-15-2004, 08:21 AM
Yes, you would place a package statement at the top of the file. The file must be in the corresponding directory.

package handling;
// File is in root/handling

Then you would import the file into another file using the import statement.

import handling.*;
//or
import handling.ErrorCounter

Regards.

jrthor2
09-15-2004, 09:32 AM
Where then do I put where the user should go based on the error count? If th user gets 3 errors, they go to a customer service page, otherwise they return the original page they were on?

Khalid Ali
09-15-2004, 09:45 AM
just a quick addition here...if you are importing any libraries,classes in any of Java classes,make sure that you always import exactly what you need such as buntine pu in the post above
import handling.ErrorCounter
imports with a * are not preferred, as a matter of fact is considered extremely bad practice any more in real life...

And one more thing,if you want to use jsp pages,then try to learn struts framework(since you mentioned J2EE as well)
And in a project where you are using J2ee framework,its extremely adivesable to use Struts.

jrthor2
09-15-2004, 09:47 AM
We are using the Struts framework

Khalid Ali
09-15-2004, 09:51 AM
Originally posted by jrthor2
We are using the Struts framework

not sure how your app works but if the above is true then importing a single class in your jsp page is not a good practice,since this must be taken care of in your Action classes( or may be a filter that all of the pages access)

jrthor2
09-15-2004, 10:01 AM
Ok, then what would be a good practice? How would you go about implementing this counter class that can be reusable by multiple pages?

Khalid Ali
09-15-2004, 10:06 AM
as you said you are using J2EE framework,so in that you can have a filter of sorts that usually is the entry point for every page in your application. You can implement such functionality in that....

The above suggestion may be true or not..since I have no idea how your actuall application logic is laid out..

jrthor2
09-15-2004, 11:42 AM
I'm not quite sure what you mean by having a filter as an entry point. We want a way to capture if the user enters a userid/pw and they don't match or are on file, increment a counter and after 3 bad attempts, be directed to a customer service page.

When you say filter, you mean using page synchronization? We are already going to be using that.

Khalid Ali
09-15-2004, 12:39 PM
:confused: :confused:

Here is what should work.
Since you are using struts, I am presuming you have something like this

Login.jsp

LoginAction.java
LoginForm.java

create a variable in the action class say int attemptsCtr = 0;

now when user tries to login, in the action class look for a request variable

request.getParameter("attemptsCtr");
if its not null and has value then convert that value to integer and assign it to
attemptsCtr...
now process that if this value is <3 then increment it by 1 and then reset the request object
attemptsCtr++;
request.setParameter("attemptsCtr",String.valueOf(attemptsCtr ));

else if its equal to 3 then whatever you want to do

I don't like using sessions much so here is the next part...
create a hidden field in the jsp
<input type="hidden" name="attemptsCtr" value="<bean:write name="attemptsCtr"/>"/>

thats about it...

jrthor2
09-15-2004, 12:46 PM
Ok, but that would be specific to logining in, right? I want it to be pretty "modular" where I can use this on other pages too, that might have different fields for user input.

jrthor2
09-15-2004, 01:24 PM
Also, could you post the code for if not null stuff, I tried getting this to work (just for my login page) but don't know all the code. Here is what I have so far (not sure if it's right or not)


package webproject.actions;

import java.util.Collection;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import java.util.ArrayList;
import java.util.HashMap;

import webproject.forms.LoginFormBean;
import webproject.util.beans.NavBean;

/**
* @version 1.0
* @author
*/
public class LoginActionAction extends Action {

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

ActionErrors errors = new ActionErrors();
ActionForward forward = new ActionForward();
// return value
LoginFormBean loginFormBean = (LoginFormBean) form;

int attemptsCtr = 0;

try {
request.setAttribute("loginFormBean", loginFormBean);


} catch (Exception e) {

// Report the error using the appropriate name and ID.
errors.add("name", new ActionError("id"));

}

// If a message is required, save the specified key(s)
// into the request for use by the <struts:errors> tag.

if (!errors.isEmpty()) {
saveErrors(request, errors);
}
// Write logic determining how the user should be forwarded.
request.getParameter("attemptsCtr");
if (attemptsCtr < 3) {
attemptsCtr++;
request.setParameter("attemptsCtr",String.valueOf(attemptsCtr ));
} Else {
forward = mapping.findForward("<cust_serv>");

}

forward = mapping.findForward("<success>");

// Finish with
return (forward);

}
}

ray326
09-15-2004, 01:38 PM
Originally posted by jrthor2
Ok, but that would be specific to logining in, right? I want it to be pretty "modular" where I can use this on other pages too, that might have different fields for user input. If you put the object into the session then it will be available for any other object running under that session. It can be incremented and tested from any JSP or other servlet or Struts action.

BTW, the above code won't compile and it's a bad idea to use angle brackets in the Struts data.

jrthor2
09-15-2004, 01:41 PM
What is wrong with the code I have so far? Do you mean the angle brakets in the forward mapping statements? What do you mean put the object into the session, how do I do that?

Khalid Ali
09-15-2004, 02:16 PM
first of all putting anything in sessions should be an absolute last thing to do.
Second here is your login validation code should look like

String paramAttempts = request.getParameter("attemptsCtr");
if(paramAttempts!=null && !paramAttempts.equals("")){
try{
attemptsCtr = Integer.parseInt(paramAttempts);
}catch(NumberFormatException nfe){
//put some logic here
}
}
//now you have value in the attemptsCtr
if (attemptsCtr < 3) {
attemptsCtr++;
request.setParameter("attemptsCtr",String.valueOf(attemptsCtr ));
} Else {
forward = mapping.findForward("<cust_serv>");

}

make sure that you do have a hidden field in the jsp page....

ray326
09-15-2004, 02:33 PM
What is wrong with the code I have so far?} Else {
Do you mean the angle brakets in the forward mapping statements?Yes
What do you mean put the object into the session, how do I do that?:rolleyes: That's scary. You REALLY need to learn the basics before you start writing code. The session is an object associated by the container with the user's long term (multi-request) interaction with the web container. You store things in there that should persist across all the HTTP transactions that happen during that user's "session." Since you will have at least three HTTP transactions causing your example failure, the associated information must be kept in the session.

In the action or servlet,

your.package.ErrorCounter errCount = new your.package.ErrorCounter();
...
session.setAttribute("counter", errCount);

In the JSP,

<jsp:useBean id="counter" scope="session" class="your.package.ErrorCounter" />

ray326
09-15-2004, 02:43 PM
first of all putting anything in sessions should be an absolute last thing to do. Things should go where they need to go. The Session is the right place for session things that ought to be cached relative to a session, e.g. an object representing the user of the session, a collection of shopping cart items, objects supporting transactional integrity, etc.

Khalid Ali
09-15-2004, 02:54 PM
Originally posted by ray326
Things should go where they need to go.
could not agree more, however, putting important data in session could mean security problems,unless extreme security measure are not implemented.Im my practice, I try to extremely reduce the use of session.I just use request and the jsp page typically for most of the needs...on the server side...ejbs are already cached...

jrthor2
09-20-2004, 11:26 AM
Ok, I copied your code into a new action class called ErrorCounterAction.java and I get the same error on the } else { line. Here is the code


package us.test.webproject.actions;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import java.util.ArrayList;
import java.util.HashMap;


/**
* @author
*
* To change the template for this generated type comment go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
public class ErrorCounterAction extends Action {

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {

String paramAttempts = request.getParameter("attemptsCtr");
if(paramAttempts!=null && !paramAttempts.equals("")){
try{
attemptsCtr = Integer.parseInt(paramAttempts);
}catch(NumberFormatException nfe){
// put some logic here
}
}
// now you have value in the attemptsCtr
if (attemptsCtr < 3) {
attemptsCtr++;
request.setParameter("attemptsCtr",String.valueOf(attemptsCtr ));
} Else {
forward = mapping.findForward("<cust_serv>");

}
// Finish with
return (forward);

}
}


I get a syntax error and it points to the { after the else.

ray326
09-20-2004, 12:22 PM
Originally posted by jrthor2
I get a syntax error and it points to the { after the else. It's not AFTER the "else" it IS the "Else"!

jrthor2
09-20-2004, 12:34 PM
I changed the Else to else and it fixed that line, but now I have 4 errors that all point to the attemptsCtr saying "attemptsCtr cannot be resolved"?? It points to all refences of this variable.

I also get forward cannot be resolved.

UPDATE
I beleive I fixed all these errors, I don't get them anymore, but when I try to run my login.jsp page, I get the below java error:

[Servlet Error]-[Cannot find bean attemptsCtr in any scope]: javax.servlet.jsp.JspException: Cannot find bean attemptsCtr in any scope

ray326
09-20-2004, 02:47 PM
It should be a response attribute, not a request parameter.

jrthor2
09-20-2004, 02:52 PM
sorry, not following where you mean it should be a response attribute? In my login.jsp page? In my ErrorCount action class?

Thanks for all the help

Khalid Ali
09-20-2004, 04:45 PM
here is your action class

public class ErrorCounterAction extends Action {

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
int attemptsCtr= 0;//do not declare this valriable as a global variable.
String paramAttempts = request.getParameter("attemptsCtr");
if(paramAttempts!=null && !paramAttempts.equals("")){
try{
attemptsCtr = Integer.parseInt(paramAttempts);
}catch(NumberFormatException nfe){
// put some logic here
}
}
// now you have value in the attemptsCtr
if (attemptsCtr < 3) {
attemptsCtr++;
request.setParameter("attemptsCtr",String.valueOf(attemptsCtr ));
} else {//Else is used in VB and family of languages
forward = mapping.findForward("<cust_serv>");

}
// Finish with
return (forward);

}
}

for the above to work you must have the following in your jsp page

<input type="hidden" name="attemptsCtr" value="<bean:write name="attemptsCtr"/>"/>

the text in bold is what seemd to be incorrect....

jrthor2
09-21-2004, 07:15 AM
When I take out my int attemptsCtr = 0 line, I get errors wherever attemptsCtr is that say "attemptsCtr cannot be resolved". Also, what is wrong with the else part? If I make this "Else" instead of "else", I get a syntax error:

Syntax error on token "{", "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "++", "--" expected

but then the "attemptsCtr cannot be resolved" errors go away???

I do have this in my login.jsp page:

<input type="hidden" name="attemptsCtr" value="<bean:write name="attemptsCtr"/>"/>

I am putting this error counter code in a seperate class and calling it within my LoginAction class like this:


ErrorCounterAction errCount = new us.riteaid.crm_v1webproject.actions.ErrorCounterAction();
request.setAttribute("attemptsCtr", errCount);


Is this how I would call this ErrorCounter class within my LoginAction class?

ray326
09-21-2004, 02:45 PM
Also, what is wrong with the else part? If I make this "Else" instead of "else", I get a syntax error: Ok this is the THIRD time I've answered this one. Maybe if I type slower and in bold.

The string "Else" does not mean anything to Java. The correct string for the else token is "else". Java is case sensitive. Tokens that begin with capital letters are meant to be class names; not instance names, not control structure tokens.

Else is wrong

else is right


I still maintain that this counter should be a session attribute.

jrthor2
09-22-2004, 07:10 AM
Ok, I got your point the first time. I said that it worked when I changed it to "else". I spoke with some other people here and this is how we would like it to work, instead of making a class to import. When you come to the login page, it sets a session variable "counter". If you login with the wrong info, the login action class checks this counter, if it less than 3, it increments the counter and takes them back to the login page. If it is greater than 3, it takes them to a customer service page. If the user credentials are correct, the login action class forwards them to a success page and the session counter is reset to 0. Could you or someone help me accomplish this?

ray326
09-22-2004, 01:24 PM
I've started a little example for you with the intention of replying to your other thread with it. Maybe tonight. It has the counter bean, a servlet for the login action and three JSPs: login, success, failure. I used straight MVC to keep the additional Struts baggage out since this is so trivial.

jrthor2
09-22-2004, 02:06 PM
thanks!!!

I actually got something working, setting a counter in the session, my login action class reads the session variable and if we caught any erros, increments the variable. If the variabble is greateer than 3, it forwards you to a customer service page.

ray326
09-23-2004, 12:13 AM
Here's the little sample. The "trick" here is that a JSP can automagically put a bean into any context simply by referencing it there in the first place.

jrthor2
09-23-2004, 10:17 AM
When I take your CounterBean.java code and replace my error counter code, I get this error in websphere:

The public type CounterBean must be defined in its own file.

What does this mean?

UPDATE
I got your code to work with mine, thanks a ton!!!! One other thing. How would I get your CounterBean to accept a maxlimit limit, so that if a different page wants 5 retries instead of 3, I could pass in a maxlimit size of 5, or if the maxlimit size was empty, it uses a default of 3?

Thanks again for all your help, I really appreciate it!!!!

ray326
09-23-2004, 12:29 PM
I'd do that by changing the action to compare against the value of a request parameter like "maxCount" and then I'd put that as a hidden field in the form on the login JSP.

<input type="hidden" name="maxCount value="5">

There are stealthier alternatives but they would require a rework of the counter bean so IT knew what the max count was.

jrthor2
09-23-2004, 12:32 PM
could you show me how to pass it to the counter bean, I believe this is the way we want it to work?

ray326
09-23-2004, 01:54 PM
I'm not sure what you're asking. Do you want the counter bean to know about the max count or do you want the action responsible for that? The former is more secure.

ray326
09-23-2004, 09:00 PM
Ok, here's a bit of a clean up with a more intelligent counter bean driving the lot.

jrthor2
09-24-2004, 07:20 AM
This is great, thanks a million for all your help!!!!!!!!!!!!!!!!!

jrthor2
09-24-2004, 09:43 AM
I came across another issue. When I login succesffuly and go to another page that has a form on it that I want to use this counter bean for, how do I reset the counter to 0 only the first time they load the page, so I can have a counter with 10 retries, but starts at 0 and counts up?

ray326
09-24-2004, 10:38 PM
Do it in the action that forwards to the other page. Get the counter reference from the session, reset(); setMaxCount(10); forward away.

jrthor2
09-27-2004, 07:11 AM
Thanks, I had figured it out.

Again, thanks for all your help, it is greatly appreciated!!!