• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Ron McLeod
  • paul wheaton
  • Jeanne Boyarsky
Sheriffs:
  • Paul Clapham
  • Devaka Cooray
Saloon Keepers:
  • Tim Holloway
  • Roland Mueller
  • Himai Minh
Bartenders:

Problems writing a controller servlet which deletes user records from mySql

 
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The application flow is quite straightforward. There is a jsp page which gives a list of users. Upon clicking a DELETE hyperlink, the below DeleteUserServlet is called and uses a DAO.delete(user) method.

I'm stuck on how to set the user object. Do I create a new user object (User user = new User())? Do I pull in the user from the prior user list using the session attribute (User user = session.getAttribute("user))? Is there some other method for pulling in the user object and using the object to delete the user?

My class is as follows. I've also include an extract of the error trace. Please let me know if I'm not being clear or you need more information. Thanks in advance!





 
Sheriff
Posts: 28413
102
Eclipse IDE Firefox Browser MySQL Database
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So that JSP page which outputs a list of users: presumably it didn't store all of them in the session? It's certain that it didn't store all of them in the session under the name of "user", since that can only refer to one object.

It's more likely that the user ID is a parameter of the request, since the user is just selecting one of the 529 users which were displayed. In that case I expect you'd get a User object from the database by using the user ID, or whatever the key for the User object might be.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Paul,

Thanks for your response.

So that JSP page which outputs a list of users: presumably it didn't store all of them in the session? It's certain that it didn't store all of them in the session under the name of "user", since that can only refer to one object.



Correct. The list of users is handled by a different servlet (DisplayUsersServlet) which is rendered by a users.jsp. The Delete action (and corresponding DeleteUserServlet) is a link on the right for each user in the user list.

The primary key is the emailAddress value for each user. The DAO method (in the UserDB class) for deleting the user is:



So I'm assuming you delete the user by getting the parameter for the selected user's e mail address, using something like:



In the DeleteUserServlet. Is that correct?

If that is correct, how should I get and set the session attribute? Do I even need to use a session attribute or is it sufficient just to pass the key as a parameter, create a new user object and call the DAO delete from the user object like:

User user = new User();

Thanks in advance!
 
Paul Clapham
Sheriff
Posts: 28413
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Your servlet receives an e-mail address as a parameter. You should use this to get a User object somehow (don't ask me how, I know nothing about your system) and then pass that User object to the delete(User) method.

As for whether you should put anything into the session, let me just ask this: Does deleting a user require you to keep track of any other information which will be used in future requests?
 
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Do the user records not have a proper primary key? Using something like an email address is a really poor and error prone way to fetch data from the DB.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

You should use this to get a User object somehow (don't ask me how, I know nothing about your system)



What do you need to know about my system?

Workflow looks something like this:

UsersDisplayServlet ---> users.jsp(lists a bunch of users) ---> 2 sets hyperlinks calling 2 separate actions for each user listed (update and delete)

---> CLICK DELETE ---> Calls DeleteUserServlet (which deletes based on the email address of the selected user in user.jsp

Is the above a clear workflow? Do you know more about my system now?

My problem is precisely HOW to get the User object. Whether to set a new User object using the new keyword OR to use the session attribute (from the UsersDisplayServlet) to get the user object:




Does deleting a user require you to keep track of any other information which will be used in future requests?



Yes it does require keeping track of other information, so given the above work flow my question is how i should use the email parameter and session object (from the user list) to pass the user object in the DeleteUserServlet

 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Bear,

I thought so too but I"m getting this from a book (Java Servlets and JSPs by Murach to be exact). It's one of the first times i've seen a DB /JDBC app that doesn't use a numeric PK, but I'm reluctant to deviate from the example in the book at this point by creating a proper PK. I will create my own DB schema once i have a better grasp of the concept of the User object and how to correctly use it.
 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
OK, just be aware that using a business value in place of a (or worse, as a) non-semantic primary key is not the best of ideas.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm kind of puzzled that an author of this caliber would break such a cardinal rule. Here's what I figured out in relation to my original problem.

- The session attribute value for the list of users is called ('users"), which is set in the DisplayUsersServlet which returns an ArrayList of users.

- The session attribute value for the update part is called ('user'), which displays a form for the selected user

This tells me that I should pass the users session attribute in the DeleteUsersServlet. This is what I tried:



The problem is I can't seem to cast an ArrayList to a User type object and I get the following error:



Am I right in assuming that I need to pass the "users" session attribute in the DeleteUsersServlet? Any advice about how to deal with the ClassCastException?

I'm thinking that writing a Generics class might solve the problem but just wanted to see if there was any advice on the above from here
 
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Jay,

Did you go the Murach site and download the source code for the book? The complete code for all the servlet projects the book uses are part of the download. The download also includes the scripts to create the database. You will need Netbeans on your machines because the projects are structured for the Netbeans IDE. The deleteUserServlet is part of the downloaded exercises all you have to do is add the SQL delete statement to it.

Regarding your comment about doing your own schema please do not. The database built by the Murach script is a database with multiple tables that are related using numeric primary keys and it is used for the final Murach project that is a web site where users can create an account, browse an online catalog, select catalog items, and place an order.

Paul and Bear, regarding primary keys, Murach has a script to create the mysql database and the database does have primary keys on the records. However the interface that the book is walking the programmer through uses the email address to create a user account and the email address has to be unique in the table. Later in the book as the servlets become more advanced servlets are used that let the administrator change the email on the user account using the primary key to access the user record.
 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am on Windows XP SP3. I unpacked the Murach files into a directory called c:\murach per the book instructions. The DeleteUserServlet is here

C:\murach\servlet_jsp\netbeans\ex_starts\ch14userAdmin\src\java\user\DeleteUserServlet.java
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Margaret,

Thanks for the useful advice. Yes I did download the entire Murach code and I even deployed the final example as a war file. For the particular example i'm referring to in this post (chapter 14), the email address is used as a primary key. The example does not use a numeric key. I'm on Win 2008 Server, running Netbeans 7.31. As I mentioned in my reply to Bear I have no intention of creating my own schema. I agreed with Bear that I thought using emailAddress as a PK was bad practice, but I guess the author is trying to focus the reader (in this specific example) on understanding how to work with sessions and JDBC object in an MVC framework. I'm not qualified to debate why the emailAddress is being used as the PK. I just know it's not the best practice, but it works for the purposes of this example.

I really appreciate the advice. Unfortunately I still haven't solved my problem. To repeat my prior post, my problem is how to correctly pass the user object in the DeleteUserServlet. I tried type casting the session attribute (from DisplayUsersServet) to a 'User' type object:

User user = (User) session.getAttribute("users"), but this resulted in a typeCast error.


Thus, my two questions are:

1) Is my thinking correct in using the session attribute from the users list to set the user object in the delete servlet?
2) What is the best way to deal with the TypeCast error? Should I look at writing a Generics class which would negate the need for type casting when setting user object?

I'd really appreciate if you have any insights on the specific questions above. Thanks so much for your helpful advice! J

 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jay Tai wrote:User user = (User) session.getAttribute("users"), but this resulted in a typeCast error.


That means that the scoped variable is not a User instance. No amount of casting will make it one.
 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jay you have reversed the sequence of the first lines in the servlet and you have added the httpsession that is not in the Murach servlet. The emailAddress string needs to be read before calling User with it.

The Murach servlet starts with



but your code starts with



Regarding using the email as a key... If you look at the full Murach demo site it is the user that is making an account and the user can delete the account. The user doesn't know what the PK is so they must edit their account using their email on the website. The administrator application knows the PK and uses it for actions. The email is not the Primary Key -- it is an unique identifier for each user that can be edited without altering the real PK for the table.


 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

That means that the scoped variable is not a User instance. No amount of casting will make it one.




Could you please explain further what you mean by that? How does that mean the scoped variable is not a User instance?

The scoped variable is "users" right? "users" is not an instance of User because the "users" attribute is coming from another servlet (DisplayUsersServlet)? right? Isn't the purpose of the statement that sets the User object to the session attribute("users") to make "users" an instance of User?

I'd appreciate your guidance.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jay you have reversed the sequence of the first lines in the servlet and you have added the httpsession that is not in the Murach servlet. The emailAddress string needs to be read before calling User with it.



Margaret,


Thanks for the thorough explanation! It makes sense now especially as you explained it in terms of what I was doing wrong with my code. I think I have to read up more on working with sessions, but you made the concept A LOT clearer for me! THANKS AGAIN!
 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jay Tai wrote:"users" is not an instance of User because the "users" attribute is coming from another servlet (DisplayUsersServlet)? right?


Not right. users is not an instance of User because a User isn't what was placed into the session in the first lpace. Find the code that sets the scoped variable. You will find that it's not an instance of User.
 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is the first servlet that is called, DisplayUsersServlet.java. Jay is this what your DisplayUsersServlet.java looks like?

 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Margaret,

This is what my servlet looks like and it looks to be the same as your post. These are actually questions at the end of chapter 14, so I coded this myself. I didn't see any solutions of how the code should be. Did I code this servlet correctly?

 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And if you look at line 25, you can see where the users scoped variable is created, and it is not an instance of User.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

And if you look at line 25, you can see where the users scoped variable is created, and it is not an instance of User



So just to be clear if line 25 was an instance of User, would it look like:

session.setAttribute("User", User);?

Am I right to assume that I'd have to pass an instance of User in the DeleteUserServlet when I"m in fact passing 'users'?

 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, it isn't the servlet that sets the scoped variable that you need to change, but where you are trying to fetch a user.

Start by answering this question: what is the type of the scoped variable users?
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
users is of type User?
 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No. Look at the code.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
session.setAttribute("users", users);

users is of type ArrayList
 
Paul Clapham
Sheriff
Posts: 28413
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jay Tai wrote:users is of type User?



Murach may have used a sketchy database design, but they would never be guilty of such a bad practice. Names should be meaningful. And in this case the name "users" is indeed meaningful. It refers, as it should to a list of users. A variable which referred to a single user should never be called "users", it should be called "user".
 
Ranch Hand
Posts: 33
Eclipse IDE Tomcat Server Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
how about this simple URL rewriting....

when you click on the delete button.....call a your servlet that performs the delete operation as...

/delSrv?userId=23

then in the respective servlet get that user Id with the getParameter .....

I hope you have something unique to identify each user.....

 
Bear Bibeault
Sheriff
Posts: 67754
173
Mac Mac OS X IntelliJ IDE jQuery TypeScript Java iOS
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It has already been pointed out that the user is being identified by email address.

(And, how does this have anything to do with URL rewriting?)
 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jay, if you look back at the version of the DeleteUserServlet that you posted you will see that you made some of the same mistakes in that as you did in the DisplayUserServlet you posted.

I"m getting this from a book (Java Servlets and JSPs by Murach to be exact). It's one of the first times i've seen a DB /JDBC app that doesn't use a numeric PK, but I'm reluctant to deviate from the example in the book at this point by creating a proper PK



Murach may have used a sketchy database design, but they would never be guilty of such a bad practice.




Please, no more Murach bashing. The Murach database is not sketchy, it is a nice little normalized database with numeric primary keys. The classes are correctly named. The books has received 10 horseshoes in the Javaranch book review. This thread is confusing because it is only showing snippets of the code, not the complete project, and because Jay is posting solutions he is testing after he has altered the Murach source code. There are three different versions of the Chapter 14 project. The version Jay is working with contains four servlets, four classes and three jsp's. I am posting one more servlet from the exercise but cannot post the full project because the Murach code belongs only to the users that purchase the book.

This is the users.jsp that calls the DeleteUserServlet that Jay is trying to complete.

 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Margaret,

THANK YOU for being so objective and setting things straight. For the record, Murach is one of the best books I've read. I'm just having trouble understanding how to work with sessions. I was puzzled by the lack of a numeric PK but when I looked at the complete example and read your comments i understood it. Your clear concise explanation really helps. Hopefully the Murach bashing is now behind us.

Before I review the mistakes in my code, let me step back for a sec and review some facts about the application:

1) The user variable is an object of type User created in UserDB.java which is a DAO class (the User.java is a bean class which extends Seriializable and provides the interface for creating the user objects in the DAO)
2) The users variable is an ArrayList created by using instances of the user object and returned as an ArrayList in the DAO class

Now the issue of how to get and set the session attribute is confusing for me.

If the above is correct, would it mean that the users arrayList should be passed in the DisplayUsersServlet in order to utilize the array and display the list of users?

The only mistake I can see from the DisplayUsersServlet and DeleteUsersServlet is that I have passed user instead of users attribute in the session object in the DeleteUsersServlet. I can't see what mistake I have made in the DisplayUsersServlet, especially since the servlet successfully displays the user list using the code I have posted. Granted that doesn't mean I've used the correct code, so I'd appreciate your advice if I"ve missed something out.

For the purposes of the DisplayUsersServlet however I would have thought it's more relevant to pass users attribute since we're dealing with a list. As mentioned DisplayUserServlet I modified seems to work ok and displays the user records. As another example, consider the update servlet. Here I'm getting user instead of users as a session attribute and the servlet is successfully updating the records. I can't directly see where I"m making mistakes.

Am I correcting in focusing on the way the session attribute is retrieved in the DisplayUsersServlet and DeleteUsersServlet as the mistakes I'm making? THANKS AGAIN!





 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Jay.

Go to my post in this thread from yesterday , posted Yesterday 10:30:56 AM, and look at the 9 lines of code I posted. That code is the beginning of my modified deleteUserServlet.
Then get the Murach book and look at page 473 to see another example of a servlet, addToEmailListServlet, called from a JSP. You are putting too much code into your servlets,

You should not be using the httpsession again. All you need to do is use request.getparameter as shown in the two examples to get the information ( in this case the email address ) from the jsp.
 
Jay Tai
Ranch Hand
Posts: 222
Netbeans IDE MySQL Database Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Margaret,

This is what my delete servlet now looks like:



When clicking delete from the user list I get the following error:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`murach`.`download`, CONSTRAINT `download_ibfk_1` FOREIGN KEY (`UserID`) REFERENCES `user` (`UserID`))

I guess this is to be expected since I'm not using the numeric PK and the author covers that later in the book. For now, I'd like to understand more about when and when NOT to use session objects.

1) Session objects were used in the DisplayUsersDervlet because I need to set the session attribute pertaining to the users ArrayList in order to render the ArrayList in the users.jsp. Correct?

2) In the update servlet I needed to retrieve the session attribute ("user") in order to preserve the state of the user object selected from the display list so this can be used to execute the update method in the DAO class to modified / update the selected record. Correct?

3) I do NOT need to use session objects to delete because simply getting the parameter emailAddress, using this to call the selectUser method and delete method from the DAO class is sufficient to allow the delete operation to be successfully executed. This assumes that I'm using the correct PK to execute the delete operation. Correct?

In addition to answers to the above I would really appreciate your suggestions for further reading about session objects and the use of related object instances. I'll be brushing up my knowledge on this using Murach and the official Oracle Java reference.

Thank you for your patience and valuable assistance!!
 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jay, there are many issues here...

>> When clicking delete from the user list I get the following error: Cannot delete or update a parent row: a foreign key constraint fails

One of the exercises at the back of Chapter 14 is to modify the User classes to add the search for the user pk by using the email address. The chain of events won't work until you have modified all the classes per the instructions. Earlier in the chapter Murach has examples of what the SQL code looks like in a data class. Without the user class modifications the lookup is probably returning null.

>>For now, I'd like to understand more about when and when NOT to use session objects.

If the book hasn't explained that well enough yet then I suggest going backwards and working through the chapters again until you understand why the examples work. There are articles here on Javaranch about Servlets such as this excellent article with diagrams The Secret Life of JavaServer Pages by Bear Bibeault You can search Javaranch to find threads about issues you are having.

With the Murach book the technologies are explained as you move forward through the book. When I used the Murach I found I couldn't jump into the book mid point. I had to start at the beginning. It is a course, each chapter shows a new technology and then the next chapter takes what was learned in the previous chapter and expands it adding another piece. The exercises make the reader work with the ideas by modifying the provided code to use the newly learned techniques.



 
Paul Clapham
Sheriff
Posts: 28413
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Margaret, you're doing a great job with this thread. I've given you a cow for all your good work here.
 
margaret gillon
Ranch Hand
Posts: 339
7
Tomcat Server Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A cow!

I am honored.
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic