Kuro5hin.org: technology and culture, from the trenches
create account | help/FAQ | contact | links | search | IRC | site news
[ Everything | Diaries | Technology | Science | Culture | Politics | Media | News | Internet | Op-Ed | Fiction | Meta | MLP ]
We need your support: buy an ad | premium membership

[P]
Dynamic Proxies in Java

By MSBob in Technology
Sun Sep 22, 2002 at 09:07:50 AM EST
Tags: Software (all tags)
Software

The Java progamming language has gone through a number of revisions and through its natural evolution it became a beast quite distinct from its older brother, C++. One of the fundamental differences between C++ and Java is the way the languages try to address the issue of runtime type information. C++ relies on generics and some rudimentary type information whilst Java uses no generics (for now anyway) and uses a sophisticated introspection system called 'reflection'. One of the more advanced examples of the power of Java reflection is the concept of a dynamic proxy.


Before we jump into the discussion of Java dynamic proxies it may be worth restating the purpose of the proxy pattern. The intent of a proxy is to provide a surrogate or placeholder for another object to control access to it.

In other words proxies are usually objects that reside between an interface and an implementation and intercept interface calls before they pass them to implementations.

The traditional way of implementing a proxy is to create a class that implements the desired interface(s) and forwards calls to the actual implementation. This means one proxy class per every interface/implementation pair which leads to a proliferation of classes. It also means that each proxied method has to be coded separately. For example:



public interface Foo

{

    public void doSomething();

    public void doAnother();

}

public class FooImpl implements Foo

{

    public void doSomething() throws MyException

    {

        System.out.println("Doing something...");

    }

    public void doAnother()

    {

        System.out.println("Doing something else...");

    }

}

public class LoggingProxy implements Foo

{

    private FooImpl target = null;

    public FooProxy(FooImpl target)

    {

        this.target = target;

    }

    public void doSomething()

    {

        System.out.println("Before doSomething()");

        this.target.doSomething();

        System.out.println("After doSomething()");

    }

    public void doAnother()

    {

        System.out.println("Before doAnother()");

        this.target.doAnother();

        System.out.println("After doAnother()");

    }

}



Now the above is hardly good news as we are forced to implement quite a lot of pretty repetitive code just to get some log statements out of our proxy.  Rest assured however, we can do a lot better than this.

A much nicer version of the proxy can be implemented by making use of the java.lang.reflect package. The most interesting class for our purposes is the unsurprisingly named java.lang.reflect.Proxy paired with the interface java.lang.reflect.InvocationHandler.

The invocation handler interface is simple enough to be quoted here in full:



public interface InvocationHandler

{

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

}



That's it folks! That's all we'll need to implement  for our proxy to work polymorphically on any method with any Interface/implementation pair. But in order to make use of the InvocationHandler one must also learn a bit about java.lang.reflect.Proxy. The Proxy class can be instantiated through a single static method newProxyInstance which needs an instance of a ClassLoader under which the proxy is to be defined, an array of interfaces (passed as an array of java.lang.Class) and an instance of the InvocationHandler interface. We can combine this in a single class which we will call DynamicProxy



import java.lang.reflect.Proxy;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.InvocationTargetException;

public class DynamicProxy implements InvocationHandler

{

    private Object target = null;

    public static Object newInstance(Object target)

    {

        Class targetClass = target.getClass();

        Class interfaces[] = target.getInterfaces();

        return Proxy.newProxyInstance(targetClass.getClassLoader(), interfaces, new DynamicProxy(target));

    }

    private DynamicProxy(Object target)

    {

        this.target = target;

    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

    {

        Object invocationResult = null;

        try

        {

            System.out.println("Before method " + method.getName();

            invocationResult = method.invoke(this.target, args);

            System.out.println("After method " + method.getName();

        }

        catch(InvocationTargetException ite)

        {

            //this is the exception thrown by the method being invoked

            //we just rethrow the wrapped exception to conform to the

            //interface

            throw ite.getTargetException();

        }

        catch(Exception e)

        {

            System.err.println("Invocation of " + method.getName() + " failed");

            System.err.println(e.getMesage());

        }

        finally

        {

            return invocationResult;

        }

    }

}



A few words of explanation about the invoke method are in order here, especially around exception handling. The catch block intercepts two types of exceptions. The InvocationTargetException is a java language exception that wraps around any exception that might get thrown in the target's method (e.g. InsufficientFundsException thrown from transferMoney()). All we need to do there is rethrow the wrapped exception in order to honour the original interface's contract. The second catch block catches anything that might have gone wrong with the invocation process itself. If target is a remote object there may be an Remote exception thrown for example. Dealing with those situations is usually application specific. The proxy if free to deal with the situation in any number of ways. For example, it might catch the exception and report an error for an administrator to inspect, it might rethrow the exception as a RuntimeException in which case the caller will receive the Exception in its first catch block, or in some more sophisticated implementations the proxy itself may try to recover from the error in some fashion (for example, by trying to reestablish the connection with the implementor).

Using our DynamicProxy is trivial. It merely requires us to invoke the static newInstance method whenever we want to instantiate an implementation. Using classes from our first example:



Foo aFoo = (Foo) DynamicProxy.newInstance(new FooImpl());

aFoo.doSomething();

aFoo.doAnother();



will result in invoke() intercepting doSomething() and doAnother() are called. The console output should look as follows:



Before method doSomething

After method doSomething

Before method doAnother

After method odAnother



We accomplished the same as in the first, naive implementation but now we have a completely generic framework to wrap any method call in a system. The applications of this are endless and include but aren't limited to: logging, timing, debugging, security checking, transaction control etc.

The proxy pattern is the inspiration of the concept of Aspect Oriented Programming and dynamic proxies similar to the one shown are the core tool used in implementing AOP in java through projects like AspectJ.

Even if you are not implementing an EJB application server or working towards a Java implementation of AOP chances are a dynamic proxy can make your programmer's life a lot easier and help you cut down on a significant amount of boilerplate code which is inevitably a Good Thing.

Sponsors

Voxel dot net
o Managed Hosting
o VoxCAST Content Delivery
o Raw Infrastructure

Login

Poll
Favorite pattern:
o Proxy 10%
o Adapter 5%
o Builder 5%
o Template Method 0%
o Singleton 25%
o Visitor 20%
o Prototype 20%
o Flyweight 15%

Votes: 20
Results | Other Polls

Related Links
o proxy pattern
o Aspect Oriented Programming
o AspectJ
o Also by MSBob


Display: Sort:
Dynamic Proxies in Java | 50 comments (26 topical, 24 editorial, 0 hidden)
Whoooo! (2.60 / 10) (#1)
by Elohim on Sat Sep 21, 2002 at 07:04:55 PM EST

The buzzword detector is redlining.

Care to elaborate? (5.00 / 2) (#3)
by MSBob on Sat Sep 21, 2002 at 07:10:12 PM EST

Care to pinpoint bullshit or buzzword hype is in my article?

It is an article for programmers (Java programmers specifically) and K5 is also a Technology weblog in case you failed to notice the motto. If you're not into programming go back to reading some more 9/11 stories as there is certainly no shortage of those here.

I don't mind paying taxes, they buy me civilization.

[ Parent ]
A couple instances (5.00 / 2) (#13)
by carbon on Sat Sep 21, 2002 at 10:01:19 PM EST

Care to pinpoint bullshit or buzzword hype is in my article?

Well, you don't overuse em significantly, but there are a few places where you might be using a term in a more generic way then it was intended. For example, you claim a correlation between reflection and AOP, but there's a big difference between providing well-built RTTI and providing AOP, although they're certainly related to a degree.

I also appreciate the references to Design Patterns, but it's my opinion that they're over-optimistic in a couple places about determining what was a DP and what wasn't. The Monostate pattern, for example, seems kind of silly when you can just say "all members static". The Proxy pattern seems rather close to that line IMO; you could just say 'By proxy, I mean a class used to provide a regulated interface to another class.' and not bring in the verbose pattern specification at all.

There are a few more instances like that. These are all minor things, certainly, and they don't take away much from the important content. But they're there, and I can see where someone might come to the impression that it's buzzword heavy. There's no need to respond with insults.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
AOP, reflection, RTTI (5.00 / 2) (#15)
by MSBob on Sat Sep 21, 2002 at 10:18:59 PM EST

I can see how the article doesn't give enough background to make a jump from reflection to AOP. However, I made certain assumptions about the audience interested in reading this. Number one is that they know java and know reflection at least in concept. Number two is that the have had a need to proxy something in their code in the past and had to implement it the old and nasty way.

I provided links for the curious amongst us so they can read up on AOP and AspectJ.

Finally you can easily claim that patterns as a term has become seriously overstated. Just look at the 'patterns' section on theserverside.com. Alas, the proxy pattern is one of the original Gang of Four patterns. And it is not about 'some object implements an interface'. The point of the proxy is that you have one more level of runtime indirection where a lot can happen. Security access check may be invoked, DB transaction may be initiated, Object pool may be search to find the best target etc. The possibilities are only limited by your imagination and the number of situations where the proxy pattern comes helpful is quite larage.

I don't mind paying taxes, they buy me civilization.

[ Parent ]
Just a moment (5.00 / 2) (#25)
by carbon on Sat Sep 21, 2002 at 11:51:51 PM EST

The point of the proxy is that you have one more level of runtime indirection where a lot can happen. Security access check may be invoked, DB transaction may be initiated, Object pool may be search to find the best target etc. The possibilities are only limited by your imagination and the number of situations where the proxy pattern comes helpful is quite larage.

I agree completely; runtime-selectable redirection is highly useful, but this concept is not the same thing as the Proxy pattern. I could do algorithm selection on the side of a client of a library with function pointers or functors or anything that acts like either of the previous two. I could do it with a polymorphic ImplementationThingie class which the client passes to methods that are appropriate for it. Or I could use an externally interpreted language and throw dynamically generated code at it.

Or I could have the language catch method calls and reroute them to a handler that I specify, without having to make a class binding to represent this relationship. Certainly, your technique is impressive, and has a lot of advantages; I'm not debating that. My problem was that you seemed to be closely pairing the highly generic pattern idea of a Proxy and your more specifically implemented technique. Your technique is only one of many different ways that a Proxy could be done, due to the genericity of the idea (ahem, pattern).
To use an extreme example, I'm saying you're talking about the use of 'if' as implementing the idea of 'conditional' completely. This is true, but misleading; although its possible to do all the things that a conditional does with an if, you seem to be saying that the idea of a conditional is the same thing as the implementation of an if.

This is an extreme example indeed; you didn't say this about your dynamic technique and the Proxy pattern, but I merely felt it to be implied. This is kind of silly; there is no 'Conditional' pattern, even though this can (and has been) implemented object-orientedly, because the concept is simply to broad to nail down to any specific technique or example as encompasing it, or any specific situation as encompasing it's applicability. This is my only issue with the Proxy pattern; it's almost as though the Gang of Four wished to take the general idea of runtime-settable execution redirection and make it into something specific, complete with guidelines for use and formal specifications to follow.

But anyways, it isn't as big a deal as I make it sound; I created the above pathological case only to explain where I was coming from, not to suggest that either you or the GoF were anywhere near that far past the line out into Jupiter orbit.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
I didn't say bullshit (5.00 / 1) (#41)
by Elohim on Sun Sep 22, 2002 at 09:28:04 AM EST

I said buzzword, which is a completly different thing.  Anyway,  I think carbon covered much of my original complaint.

[ Parent ]
Java (none / 0) (#50)
by pb on Wed Sep 25, 2002 at 03:19:10 PM EST

Just talking about Java is enough, thanks, seeing as how Java is a "simple, object-oriented, distributed, interpreted, robust, secure, architecture-neutral, portable, multithreaded, dynamic, buzzword-compliant, general-purpose programming language" ...
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]
java.lang.reflection (5.00 / 4) (#10)
by arthurpsmith on Sat Sep 21, 2002 at 09:30:06 PM EST

I've been thinking I needed to learn more about the reflection stuff as we get more into java at work, but I'd been scared off thinking it was way too complicated. This is a nice, relatively simple example of what you can do - thanks Bob!

Energy - our most critical problem; the solution may be in space.


Reflection's easy... (5.00 / 4) (#12)
by MSBob on Sat Sep 21, 2002 at 09:42:30 PM EST

Think of reflection as a means of accessing your objects' metadata. You have them objects in your program and what reflection allows you to do is come and ask: "hey you, what type are you of?". Then you can find out about your object's class. Once you have its class you can ask specifics about it such as what methods are provided, what fields are in it and so on. The dynamic proxy is actually one of the more advanced concepts of using reflection where the proxy basically goes to an object and says: "tell me what interfaces you implement 'cause I want to implement them too". The whole trick relies on the fact that in java you can have a completely new type created at runtime.
I don't mind paying taxes, they buy me civilization.

[ Parent ]
Yes (5.00 / 1) (#42)
by greenrd on Sun Sep 22, 2002 at 09:46:48 AM EST

In fact, in principle, the dynamic proxy generator could be completely rewritten in pure Java, for those still sticking with JDK1.1 or JDK1.2. Although, you would have to have a good knowledge of .class files to write one that had an acceptable performance.


"Capitalism is the absurd belief that the worst of men, for the worst of reasons, will somehow work for the benefit of us all." -- John Maynard Keynes
[ Parent ]

ERRATA (5.00 / 3) (#19)
by MSBob on Sat Sep 21, 2002 at 10:28:21 PM EST

A code troll sneaked in a few errors that will prevent the example code from compiling. Here's the errata courtesy of opensorcerer quoted in full from his editorial comment:
"There are some syntax errors though.. :)
  • the before and after println's need extra )'s.
  • getMesage needs to become getMessage.
  • target.getInterfaces needs to be targetClass.getInterfaces.
Oh yeah, and running this code immediately rooted my machine. Er, just kidding."
Big thanks to opensorcerer for pointing them out!
I don't mind paying taxes, they buy me civilization.

Some comments and a question on the example (5.00 / 3) (#28)
by Pseudonym on Sun Sep 22, 2002 at 12:51:17 AM EST

First of all, if all you want to do is wrap members for logging, the first proxy mentioned is unnecessarily complex. The private member should not be of type FooImpl, it should be of type Foo. The reason for this should be obvious: Not only do you only use the Foo interface, but this lets you use the same proxy for all implementations of Foo. So you don't need a proxy class for each interface/implementation pair. You only need one for each interface.

Secondly, it can be done in C++.

Thirdly, my main beef with this approach is its very flexibility. Because it's designed to cater for all interface/implementation pairs, it's difficult to customise it for a specific problem. For example, if you find you need some more verbose logging in a specific situation (say, you want to dump a specific method parameter when a certain method is called on a certain implementation), your dynamic proxy will start to get quite unweildy.

Fourthly, and this is a non-rhetorical question, incidentally, can you proxy a proxy using this approach? Is DynamicProxy powerful enough to be able to wrap a DynamicProxy? What's the run-time cost if you attempt this?



sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
Language wars (5.00 / 2) (#29)
by ucblockhead on Sun Sep 22, 2002 at 01:04:57 AM EST

Saying that "it can be done in language foo" is pretty useless as most professional programmers aren't in a position where they can change languages at the drop of a hat.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
but it's nice to know... (3.00 / 2) (#31)
by MSBob on Sun Sep 22, 2002 at 01:13:09 AM EST

It's nice to know it can be done in C++. I used to think that C++ was too statically typed for that kind of stuff to be feasiblie. But with that overloaded arrow operator it looks like a nice resolution to the problem... I don't think he was trying to ignite a language war there...
I don't mind paying taxes, they buy me civilization.

[ Parent ]
Understood, but... (5.00 / 1) (#32)
by Pseudonym on Sun Sep 22, 2002 at 01:52:55 AM EST

I mentioned it for two reasons. The main one was carbon's editorial comment wondering if it could be done with templates and the overloaded -> operator. The other reason is that MSBob explicitly mentioned C++ in the opening of the article.



sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
[ Parent ]
Sorry about that. (5.00 / 1) (#44)
by ucblockhead on Sun Sep 22, 2002 at 11:52:36 AM EST

My knee jerked a bit. I apologize.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
Perhaps they should be though (none / 0) (#47)
by ph317 on Mon Sep 23, 2002 at 11:02:03 AM EST



[ Parent ]
Both concerns addressed :) (3.66 / 3) (#30)
by MSBob on Sun Sep 22, 2002 at 01:09:56 AM EST

The proxy doesn't need to get unwieldy. My example is quite simple but in real life the proxy would just act as a broker that would offload any meaningful work to a series of interceptors (such as Logging Interceptor, Transaction Interceptor, Security Interceptor etc).

The dynamic proxy can proxy calls to other dynamic proxies. If you query the Class object of the object returned from newProxyInstance for its implemented interfaces you will see that it returns the interfaces array passed to newProxyInstance. You can (and often want to) chain proxies dynamically by passing the interface array on construction. I use this at work where one dynamic proxy is used for controling normal transaction/security stuff and wraps every system component. Besides normal components we have web services that are consumed by our app and they use dynamic proxies to implement wsdl mandated interfaces at runtime. Effectively I have a call chain where outer proxy's invoke() invokes the inner proxy's invoke() which in turn calls out to the web services engine (GLUE in our case).

I don't mind paying taxes, they buy me civilization.

[ Parent ]
Cool, thanks (5.00 / 1) (#35)
by Pseudonym on Sun Sep 22, 2002 at 01:54:46 AM EST

That's exactly what I wanted to know.



sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
[ Parent ]
Well, ... (5.00 / 2) (#40)
by Simon Kinahan on Sun Sep 22, 2002 at 08:56:45 AM EST

<language-war>
Stroustrup, as ever, completely misses the point. In the scheme he describes the proxy has no common supertype with the class it is proxying for. It is therefore impossible to write "normal" client code and having it work with the proxy without modification. That makes the scheme described next to useless for many of the applications of dynamic proxies in Java.
</language-war>

Dynamic proxies, or rather their invocation handlers, can indeed get unwieldly. Most of their applications are in debugging and similar kinds of activities. If you want to do different ad-hoc things for the various methods that get called, one approch is to use mutliple layers of proxies and several invocation handlers. Another would be to extend the mechanism so that different method calls can be dispatched to different handlers.

A dynamic proxy can indeed wrap other dynamic proxies. The proxy, once it is generated, is just a regular object. Dynamic proxies involve a largish constant cost in every method call, because they use the reflection mechanism. Using two proxies is twice as expensive as using one. You wouldn't want to do it in a tight inner loop, but in typical Java applications, which are accessed over the network, the cost is small in comparison.

Simon

If you disagree, post, don't moderate
[ Parent ]

cost (5.00 / 1) (#45)
by justo on Sun Sep 22, 2002 at 12:02:50 PM EST

i'd also be very interested in knowing what the overhead would be. i've tended to stay away from reflection because of it (tho' it may just be in my mind -- i haven't done any concrete comparisons).

other than that, it certainly looks like a more elegent approach to proxying that i'll have to experiment around with a bit.

[ Parent ]

Excellent tech story (5.00 / 2) (#39)
by bodrius on Sun Sep 22, 2002 at 06:16:01 AM EST

Concise, instructive and useful.

I had been delaying checking up dynamic proxies for a while, since I haven't had the need to play with reflection for a while and it wasn't a priority.

It's actually simpler than I expected, considering its power. In retrospect, I might have solved some recent problems this way rather than with the old-fashioned alternative. I'll have to try and see if it works better.

I'm a Java guy myself, but I do wonder if reflection is used like this in other languages?
Freedom is the freedom to say 2+2=4, everything else follows...

Aspect-Oriented Programming (5.00 / 5) (#43)
by greenrd on Sun Sep 22, 2002 at 11:05:30 AM EST

The proxy pattern is the inspiration of the concept of Aspect Oriented Programming and dynamic proxies similar to the one shown are the core tool used in implementing AOP in java through projects like AspectJ.

Actually, both of these statements are incorrect. Firstly, it is arguable that aspect-oriented programming was inspired more by metaobject protocols, which predate the concept of design patterns in computer science (which can be dated approximately to the original Gang of Four book in 1995, IIRC). Gregor Kiczales, the person who coined the term "aspect-oriented programming", was on the team that created the Common LISP Object System (CLOS), a powerful metaprogramming system for LISP. My sources tell me that aspect-oriented programming was something that was developed to solve some of the same challenges as MOPs, but in a way that was attractive and easy/convenient to use for the masses. I think Kiczales and his team have succeeded pretty well at this.

Secondly, in AspectJ you do not program your AOP stuff using dynamic proxies, and nor does the AspectJ compiler always use dynamic proxies to implement them. The author has probably confused AspectJ with another aspect-oriented or pseudo-aspect-oriented approach.

In AspectJ the above example is quite simple to implement, if you want all calls - or all calls from a certain group of packages - to all objects of a certain class to be intercepted. If you want to proxy only some instances of a certain class and not others, you may still end up using an actual proxy.

Here is a rough-and-ready translation of the above into AspectJ, which assumes you want to wrap all objects implementing Foo:

public aspect Logging {

Object around (): execution (public * Foo+.* (..)) {
System.out.println("Before " + thisStaticJoinPoint);
try {
return proceed ();
} finally {
System.out.println("After " + thisStaticJoinPoint);
}
}

}

The aspect is applied automatically ("woven in") by the compiler. There is no need for the programmer to create any proxies at all. It "just works".

Worth checking out. Although AspectJ (aspectj.org) is an open source project it has been funded by DARPA and PARC, and it is already at the stabilised stage (no major incompatible changes to the language will be introduced in future), so it actually has some decent documentation. :-)


"Capitalism is the absurd belief that the worst of men, for the worst of reasons, will somehow work for the benefit of us all." -- John Maynard Keynes

AspectJ's implementation (3.00 / 2) (#46)
by MSBob on Sun Sep 22, 2002 at 03:41:31 PM EST

I know you don't use dynamic proxies when writing your apsects. I never claimed that in the article. What I said is that dynamic proxies are used to implement aspects internally. At least I think (hope) they are. It would be foolish to do it any other way in java.
I don't mind paying taxes, they buy me civilization.

[ Parent ]
Not the case (5.00 / 1) (#49)
by greenrd on Tue Sep 24, 2002 at 01:35:01 PM EST

Not true. This is an example of "when you only have a hammer, everything looks like a nail" principle.

You can write an aspect that is essentially "static". Have you ever heard of a weaver? This works by rewriting code, not by wrapping classes.

In fact the reverse of your statement is true. In some scenarios it would be foolish to use dynamic proxies. In general all wrapper-based solutions have at least four well-known major deficiencies - I'll paraphrase from a draft paper I'm writing:

  • You have to remember to wrap an object whenever you receive it from a third-party API, if it is created by that third-party API. (Unless you have dynamic weaving, but IMO that cannot always be used on third-party code because of copyright law, although IANAL)
  • Wrappers violate the object identity principle - an object should have one and only one identity.
  • As a consequence of the above, code that holds references to the real object rather than the wrapper can accidentally leak references to the real object. For a seamless aspect-oriented language such as AspectJ this really militates against using any kind of wrappers, because it produces unwanted side-effects.
  • Not all concerns can be composed as independent wrappers.

"Capitalism is the absurd belief that the worst of men, for the worst of reasons, will somehow work for the benefit of us all." -- John Maynard Keynes
[ Parent ]
Facets (none / 0) (#48)
by Scrop on Mon Sep 23, 2002 at 02:45:19 PM EST

There is a runtime implementation of something similar which is a bit faster than a Proxy since it involves no reflection, and which offers a framework to build up some security features.

http://www.cse.buffalo.edu/~crahen/projects.html#facet

Dynamic Proxies in Java | 50 comments (26 topical, 24 editorial, 0 hidden)
Display: Sort:

kuro5hin.org

[XML]
All trademarks and copyrights on this page are owned by their respective companies. The Rest 2000 - Present Kuro5hin.org Inc.
See our legalese page for copyright policies. Please also read our Privacy Policy.
Kuro5hin.org is powered by Free Software, including Apache, Perl, and Linux, The Scoop Engine that runs this site is freely available, under the terms of the GPL.
Need some help? Email help@kuro5hin.org.
My heart's the long stairs.

Powered by Scoop create account | help/FAQ | mission | links | search | IRC | YOU choose the stories!