A Simple Multi-Threaded Java HTTP Proxy Server
This post is to show an example of a simple multi-threaded Java HTTP Proxy Server. This sample is not fully functional for every application. It’s very simple and works fine for HTTP GET requests, but is not coded to properly handle HTTP POST requests (nor any other HTTP methods). This is strictly as an example to show how simple it is to proxy requests. This one simply records the url of all requests that are passed through it. Please let me know if you have any questions, and feel free to steal it and improve on it. Let me know what you come up with.
This first bit of code is the actual multithreaded server. It simply starts up the proxy server on a given port, takes in an HTTP request, and spawns off the request to a new thread passing the socket to the thread, and starts that thread on the request.
package proxy;
import java.net.*;
import java.io.*;
public class ProxyServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
int port = 10000; //default
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
//ignore me
}
try {
serverSocket = new ServerSocket(port);
System.out.println("Started on: " + port);
} catch (IOException e) {
System.err.println("Could not listen on port: " + args[0]);
System.exit(-1);
}
while (listening) {
new ProxyThread(serverSocket.accept()).start();
}
serverSocket.close();
}
}
This is the real meat of the application. However, it’s still a fairly simple class. It’s a thread that starts up, then receives the incoming request from the client, resends the request to the real server that the client intended to send it to (while logging the request), then receives the response from the real server, and propogates that same response to the client. Fairly simple process.
package proxy;
import java.net.*;
import java.io.*;
import java.util.*;
public class ProxyThread extends Thread {
private Socket socket = null;
private static final int BUFFER_SIZE = 32768;
public ProxyThread(Socket socket) {
super("ProxyThread");
this.socket = socket;
}
public void run() {
//get input from user
//send request to server
//get response from server
//send response to user
try {
DataOutputStream out =
new DataOutputStream(socket.getOutputStream());
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String inputLine, outputLine;
int cnt = 0;
String urlToCall = "";
///////////////////////////////////
//begin get request from client
while ((inputLine = in.readLine()) != null) {
try {
StringTokenizer tok = new StringTokenizer(inputLine);
tok.nextToken();
} catch (Exception e) {
break;
}
//parse the first line of the request to find the url
if (cnt == 0) {
String[] tokens = inputLine.split(" ");
urlToCall = tokens[1];
//can redirect this to output log
System.out.println("Request for : " + urlToCall);
}
cnt++;
}
//end get request from client
///////////////////////////////////
BufferedReader rd = null;
try {
//System.out.println("sending request
//to real server for url: "
// + urlToCall);
///////////////////////////////////
//begin send request to server, get response from server
URL url = new URL(urlToCall);
URLConnection conn = url.openConnection();
conn.setDoInput(true);
//not doing HTTP posts
conn.setDoOutput(false);
//System.out.println("Type is: "
//+ conn.getContentType());
//System.out.println("content length: "
//+ conn.getContentLength());
//System.out.println("allowed user interaction: "
//+ conn.getAllowUserInteraction());
//System.out.println("content encoding: "
//+ conn.getContentEncoding());
//System.out.println("content type: "
//+ conn.getContentType());
// Get the response
InputStream is = null;
HttpURLConnection huc = (HttpURLConnection)conn;
if (conn.getContentLength() > 0) {
try {
is = conn.getInputStream();
rd = new BufferedReader(new InputStreamReader(is));
} catch (IOException ioe) {
System.out.println(
"********* IO EXCEPTION **********: " + ioe);
}
}
//end send request to server, get response from server
///////////////////////////////////
///////////////////////////////////
//begin send response to client
byte by[] = new byte[ BUFFER_SIZE ];
int index = is.read( by, 0, BUFFER_SIZE );
while ( index != -1 )
{
out.write( by, 0, index );
index = is.read( by, 0, BUFFER_SIZE );
}
out.flush();
//end send response to client
///////////////////////////////////
} catch (Exception e) {
//can redirect this to error log
System.err.println("Encountered exception: " + e);
//encountered error - just send nothing back, so
//processing can continue
out.writeBytes("");
}
//close out all resources
if (rd != null) {
rd.close();
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Hope you enjoy and learn a little from how simple it is in Java to perform network requests, as well as multi-threading to create a somewhat useful application that can be easily extended to be much more useful. Hope this helps.
A session size monitoring servlet
This is a quick example of a servlet that will tell you the size of your session. This is helpful if you don’t have the tools built into your development suite to give you this information. I found this laying around that I had written a while back. It essentially is a simple servlet that grabs all the session attributes and writes out each to a ObjectOutputStream object. It then takes the size of the ByteArrayOutputStream object contained in the ObjectOutputStream object and displays that.
public class HttpSessionSizeServlet extends HttpServlet {
private static Logger log = LogFactory.
getLogger(HttpSessionSizeServlet.class);
public void doGet(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
if (session != null) {
Enumeration e = session.getAttributeNames();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream s = new ObjectOutputStream(bos);
while (e.hasMoreElements()) {
Object o = session.getAttribute((String) e.nextElement());
s.writeObject(o);
s.flush();
}
log.info("size = " + bos.size());
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//do nothing
}
}
Hope this helps.
Writing a custom generic exception handler in Struts
Exception handling in Struts is a very simple concept to grasp, once you know the tool that Struts has put in place to handle it. This tool is the org.apache.struts.action.ExceptionHandler . The ExceptionHandler mechanism allows you to configure it in the struts-config.xml file and then Struts will automagically pass any exception type it’s configured to handle to it at runtime. Here’s a simple example of how easy it is to create one of these classes .
package myapp.exc;
import org.apache.struts.action.ExceptionHandler;
//other struts imports
public class MyExceptionHandler extends ExceptionHandler {
public ActionForward execute( Exception ex,
ExceptionConfig exConfig,
ActionMapping mapping,
ActionForm formInstance,
HttpServletRequest request,
HttpServletResponse response
) throws ServletException {
//send email to support that something happened w/ stack trace included
//print stack trace to logs
ex.printStackTrace();
return mapping.findForward("login");
}
}
This method takes in several parameters (including the request/response objects) and returns the forward to where you want to take the user. After setting your class up, all you’ve got to do now is configure it in the struts-config.xml file. You add it to the global-exceptions section. Here’s an example of how to do that for 2 different handlers for 2 different types of exceptions.
<global-exceptions>
<exception
handler="myapp.exc.MyExceptionHandler"
key="standard.error.message"
path="/genericError.jsp"
scope="request"
type="myapp.exc.MyException"/>
<exception
handler="myapp.exc.AuthorizationExceptionHandler"
key="unauthorized.error.message"
path="/auth.jsp"
scope="request"
type="myapp.exc.AuthorizationException"/>
</global-exceptions>
As you can see, you can easily use what Struts has provided to setup a flexible declarative exception handling model for your application.
Hope this helps.
Writing a custom role based access control framework that integrates with Struts
This article will tell you a fairly simple way to put a custom access control framework in place for your J2EE application that will let you integrate it with the struts framework role based access control protection mechanisms. There are a few pieces to this solution:
1. A storage mechanism for the accesses (roles) per user
2. Writing these accesses into the HttpSession per user (generally in the form of an easily accessible object with helper functions on the session)
3. Override the processRoles method of the struts RequestProcessor class in order to recognize your custom roles
4. Add roles=”…” to your struts actions to protect them based on the configured roles
Ok, in order then, here we go.
For #1 – this is usually done via a relational database – whatever application database you’re using, you’ll generally store the accesses for a given user. However, you could store these in flat files, ldap, or some other mechanism if you wanted to – that’s up to you.
For #2 – here’s an object you can use to hold the roles.
public class UserAccesses {
private String userName;
private String[] roles;
public UserAccesses(String userName, String[] roles) {
this.userName = userName;
this.roles = roles;
}
public boolean hasRole(String role) {
if (roles.length > 0) {
for (int i = 0; i < roles.length; i++) {
if (role.equals(roles[i]))
return true;
}
}
return false;
}
public String toString() {
StringBuffer sb = new StringBuffer(1024);
sb.append(userName);
sb.append(" has roles: ");
for(int i=0; i
This object stores a string array of the role names per user. Now here's some code to write this object into the session. This code should be called when the user logs into the application.
List allAccessesList = new ArrayList();
//if the user has the write stories access from the db
allAccessesList.add(Constants.WRITE_STORIES);
//if the user has the read stories access from the db
allAccessesList.add(Constants.READ_STORIES);
//if the user has the delete stories access from the db
allAccessesList.add(Constants.DELETE_STORIES);
String[] allUserAccesses =
(String[])allAccessesList.toArray(new String[0]);
UserAccesses userAccessesObj =
new UserAccesses (userId, allUserAccesses);
HttpSession session = request.getSession();
session.setAttribute(Constants.USER_SESSION_ACCESSES, userAccessesObj);
On to #3 - here you have to write a custom class that overrides the processRoles method of the RequestProcessor class in struts
public class RolesRequestProcessor extends RequestProcessor {
private static final Logger log =
LogFactory.getLog(RolesRequestProcessor.class);
public RolesRequestProcessor() {
super();
}
/**
* @see org.apache.struts.action.RequestProcessor
* #processRoles(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse,
* org.apache.struts.action.ActionMapping)
*/
protected boolean processRoles(HttpServletRequest request,
HttpServletResponse response, ActionMapping mapping)
throws IOException, ServletException {
//Obtain the list of roles from action config
String roles[] = mapping.getRoleNames();
if ((roles == null) || (roles.length < 1)) {
log.debug("No role is required for running this operation.");
return (true);
}
//verify user possesses role
StringBuffer sb =
new StringBuffer("Check for required roles ....... n");
//checking in ldap roles
for (int i = 0; i < roles.length; i++) {
sb.append(roles[i]);
sb.append(", ");
if (request.isUserInRole(roles[i])) {
sb.append("Found a matching role in the ldap roles: " + roles[i]);
return (true);
}
}
// checking in custom database roles
// Check the current user against the list of required roles
HttpSession session = request.getSession();
UserAccesses userAccessesObj = (UserAccesses )
session.getAttribute(Constants.USER_SESSION_ACCESSES);
if (userAccessesObj == null) {
return false;
}
for (int i = 0; i < roles.length; i++) {
if (userAccessesObj .hasRole(roles[i])) {
sb.append("Found a matching role in the custom roles: " + roles[i]);
return (true);
}
}
//end custom roles check
//invoke declarative exception handling
sb.append("n");
sb.append("User does not have the required role");
log.debug(sb.toString() + " ");
ActionForward forward = null;
try {
forward = processException(request, response,
new my.application.AuthorizationViolationException(),
null, mapping);
} catch (Throwable e) {
e.printStackTrace();
}
// forward user to the authorization error page...
if (forward != null) {
log.info("Forward to authorization error page");
processForwardConfig(request, response, forward);
}
return (false);
}
}
Finally #4 - here you just add the roles attribute to your struts configuration in order to get struts to check for the specified role(s) (multiple roles, is just a comma-delimeted group) to allow a user to perform a given action.
<action path="/myApplication/deleteStory"
type="my.actions.DeleteStoryAction" roles="DELETE_STORIES,ADMIN">
<forward name="deleteSuccess" path="/myApplication/deleteSuccess.do" />
</action>
This process has worked very well on my projects, and hopefully will on yours as well.
Hope this helps.
Transactions With Spring in Java
This post will show you how to write the code to perform transaction handling in Java using the Spring framework. There are certainly many varied ways to handle this, but this is one that I’ve found works fairly well and tends to lead to a fairly clean code base.
The code below essentially forces the block of code all to occur within a transaction, and either causes the transaction to go through with a commit (assuming everything went well), or rolls it all back if anything failed. In this particular case, there are multiple stored procedures being called that all need to pass for the entire process to be valid. It’s true that this could all be handled in one procedure, but that could make the parameters very ugly. In this situation, I think it’s better to have multiple procedures called within one transaction in the java code.
public boolean saveUser(User user){
boolean success = false;
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
Map results = null;
try{
LinkedHashMap inputTypesMap = new LinkedHashMap();
inputTypesMap.put(Constants.USER_ID,new Integer(Types.INTEGER));
inputTypesMap.put(Constants.FIRST_NAME,new Integer(Types.VARCHAR));
inputTypesMap.put(Constants.LAST_NAME,new Integer(Types.VARCHAR));
inputTypesMap.put(Constants.PHONE_NUMBER,new Integer(Types.VARCHAR));
inputTypesMap.put(Constants.EMAIL_ADDRESS,new Integer(Types.VARCHAR));
LinkedHashMap outputTypesMap = new LinkedHashMap();
AdminStoredProcedure prc =
new AdminStoredProcedure(ds,Constants.USER_SAV_PROCEDURE_NAME,
inputTypesMap,outputTypesMap,null);
LinkedHashMap inputValuesMap = new LinkedHashMap();
inputValuesMap.put(Constants.USER_ID, user.getUserId());
inputValuesMap.put(Constants.FIRST_NAME,contact.getContactFirstName());
inputValuesMap.put(Constants.LAST_NAME,contact.getContactLastName());
inputValuesMap.put(Constants.PHONE_NUMBER,contact.getPhoneNumber());
inputValuesMap.put(Constants.EMAIL_ADDRESS,contact.getEmailAddress());
results = prc.execute(inputValuesMap);
//another procedure call, hence the need for the transaction
userService.deleteUserGroupAssociation(user.getUserId());
int[] contactGroups = user.getContactGroups();
for(int i=0; i
Hope this helps.
Using ResourceBundles to handle messages in Java – ApplicationResources.properties
Java has a couple of concepts that are used as best practices in web applications that can be very useful even if you don’t intend to use them for their strict purpose. The first is a properties file and the second is internationalization (i18n – 18 letters between the i and the n).
Properties files are simple key=value files. They contain records that are in this format generally:
my.key=My Value
Internationalization is a concept that allows an application to move it’s labels of field names, descriptions, etc. to be encoded in properties files with a specific extension representing the language. These follow the 2-letter ISO 3166 country code extensions. These are very useful in web applications and allow you to extract messages at will using both manual methods as well as tag libraries.
An example of the manual method is shown below:
ResourceBundle messages = ResourceBundle.getBundle("ApplicationResources");
String adminId = messages.getString("adminuserid");
String adminPassword = messages.getString("adminpassword");
This bit of code will extract the value of the adminuserid property from the ApplicationResources.properties file and place it’s value in the adminId field, and the same with the adminPassword field.
An example of using the jstl fmt taglib in order to display a message is shown below:
<fmt:message key="label.userId"/>
This bit of code will extract the value of the label.userId property and render it on the screen.
Hope this helps.
Using Spring’s StoredProcedure and RowMapper mechanisms
One very useful portion of the Spring Framework is the StoredProcedure wrapper’s and the RowMapper objects. Together these allow you to call a stored procedure and then parse the result set back into a collection of objects with very little pain. Below is an example of how to do just this for a simple query like a user query.
First, we have the StoredProcedure class:
public class MyStoredProcedure extends StoredProcedure {
public MyStoredProcedure (DataSource ds, String spname,
Map map, String sqlOutKey, Integer returnType,
RowMapper rowmapper) {
super();
setDataSource(ds);
/* resultset has to be declared first over other declare parameters */
if (rowmapper != null) {
declareParameter(new SqlReturnResultSet(sqlOutKey, rowmapper));
}
if (map != null) {
Iterator itr = map.keySet().iterator();
while (itr.hasNext()) {
String key = (String) itr.next();
Integer value = (Integer) map.get(key);
declareParameter(new SqlParameter(key, value.intValue()));
}
}
/*
* sql out paramter has to be declared based on the order in stored
* procedures, In all our stored procedures we have it after input
* parameters
*/
if (returnType != null) {
declareParameter(new SqlOutParameter(sqlOutKey, returnType
.intValue()));
}
setSql(spname);
compile();
}
}
Next, we have the Mapper class:
public class UserMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUserId(rs.getString(Constants.USER_ID));
user.setFirstName(rs.getString(Constants.FIRST_NAME));
user.setLastName(rs.getString(Constants.LAST_NAME));
user.setOrganizationName(rs.getString(Constants.ORGANIZATION_NAME));
return user;
}
}
Next, we have to query the actual stored procedure from a DAO. Here’s a sample method that would do just such a thing:
public Collection searchUsers(User user) throws Exception {
Map lhm = new LinkedHashMap(4);
lhm.put(Constants.USER_ID, new Integer(Types.VARCHAR));
lhm.put(Constants.FIRST_NAME,new Integer(Types.VARCHAR));
lhm.put(Constants.LAST_NAME,new Integer(Types.VARCHAR));
lhm.put(Constants.ORGANIZATION_NAME,new Integer(Types.VARCHAR));
UserMapper mapper = new UserMapper();
// Call Stored Procedure
EntitlementsStoredProcedure proc = new EntitlementsStoredProcedure(
ds, StoredProcedureConstants.USER_SEL, lhm,
Constants.RESULTSET, null, mapper);
// Collect the criteria for the search
Map map = new LinkedHashMap(4);
map.put(Constants.USER_ID, user.getUserId());
map.put(Constants.FIRST_NAME, user.getFirstName());
map.put(Constants.LAST_NAME, user.getLastName());
map.put(Constants.ORGANIZATION_NAME, user.getOrganizationName());
Map results = proc.execute(map);
List resultList = (LinkedList)results.get(Constants.RESULTSET);
//iterate of results list and print
for (Iterator it=resultList.iterator(); it.hasNext(); ) {
User user1 = (User)it.next();
System.out.println(user1);
}
return resultList;
}
That’s all there is to it! This shows just how simple it is to do queries in an object oriented way, and have generic row mappers. There are full object relational mapping solutions, such as Hibernate, that do a great job of solving the working with relational data in an OO way paradigm, but they take a LOT of configuration and can be daunting if you’re not accustomed to working with them. This solution, however, I feel works very well in simpler scenarios. It also allows someone who is used to looking at code to quickly read through and get an idea of how to use this.
One point to note: this gets even simpler when using generics that are introduced in Java 1.5, but the environment I’m currently in is 1.4, so forgive me. I’ll leave the translation as an exercise for the reader.
Enjoy! Hope this helps!
Amazing Wooden Computer Cases
A good bit off topic, but here are some amazing computer cases made out of wood. Enjoy!
http://www.suissacomputers.com/
http://www.ecogeek.org/content/view/62/1/
http://www.neatorama.com/case-mod/#wood
http://www.voidedwarranty.com/PC_Case_Reviews/p2_articleid/46
http://student.dei.uc.pt/~octavio/caixa/indez_en.htm
Mapping your web server visitors in Google Earth, Part 3 (conclusion)
A few days later, but here’s the conclusion to the story. In part 2, I showed how to parse out the apache log file to get a list of IP addresses. Now all you have to do is, one by one, geolocate those addresses and write them out to a KML doc that gets displayed in Google Earth (or even Google Maps).
For geolocating, I’m using the free product by MaxMind (http://www.maxmind.com/app/ip-location) to do the lookups for the geolocation. Here’s the code to do the geolocation and write out to KML.
import com.maxmind.geoip.*;
import java.io.*;
/* sample of how to use the GeoIP Java API with GeoIP City database */
/* Usage: java CityLookupTest 64.4.4.4 */
class CityLookup {
public static void main(String[] args) {
try {
LookupService cl = new LookupService(args[0],
LookupService.GEOIP_STANDARD);
BufferedReader in = new BufferedReader(new FileReader(args[1]));
BufferedWriter out = new BufferedWriter(new FileWriter(args[2]));
String str;
out.write("<?xml version="1.0" encoding="UTF-8"?>n");
out.write("<kml xmlns="http://earth.google.com/kml/2.1">n");
out.write("<document>n");
while ((str = in.readLine()) != null) {
Location loc = cl.getLocation(str);
if (loc == null) {
System.out.println("loc null");
} else {
out.write(" <placemark>");
out.write("<name>" + str + "</name>");
out.write("<description>" + str + "</description>");
out.write("<point>");
out.write("<coordinates>" + loc.latitude + ","
+ loc.longitude + "</coordinates>");
out.write("</point>");
out.write("</placemark>n");
}
}
in.close();
out.write("</document>n");
out.write("</kml>n");
out.close();
cl.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now, all you have to do is import the file into Google Earth, or if you have a publicly available web server, you can put the file there, and have google maps pick it up by passing the file as a parameter.
I hope you’ve enjoyed reading this 3-part tutorial as much as I’ve enjoyed writing it. This could be the start of a fun project. Hope you enjoy!
Mapping your web server visitors in Google Earth, Part 2
Part 1 of this series talked at a high level about what was to be accomplished – viewing your web server visitors geographically on a map. It’s got a cool factor, but actually is quite useful for some folks.
This part of the series will show you how to take the Apache web server’s combined log format and get out the ip addresses that have visited your site. This code just parses a file, and takes the first token (first text before a space) and writes out a new line for each address. Alternatively, you could, instead of printing each line out, you could add them to a StringBuffer for better performance, then print them out. A reasonable idea would be to add them to a concrete implementation of java.util.Set so you only saw unique IP addresses. Anyhow, here’s the starter code.
import java.io.*;
public class ParseLogFile {
public static void main(String[] args) {
String newline = System.getProperty("line.separator");
try {
BufferedReader in = new BufferedReader(new FileReader(args[0]));
BufferedWriter out = new BufferedWriter(new FileWriter(args[1]));
String str;
while ((str = in.readLine()) != null) {
String[] strs = str.split(" ");
out.write(strs[0] + newline);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
This should read in the apache log file and write out to a file with a long list of ip addresses / domain names. The above code is very simple and fairly unnecessary. You could easily use OS utilities to accomplish the same thing, and you could do this for any type of log file, really. This was just an example.
The last step is taking the output file, and then geolocating each address, and creating some KML out of the addresses. That’s gonna be saved for part 3. See you soon.