Event bus review - java

I'm starting with GWT and learning Event bus concepts now. I find this solution extremely complicated. So I tried to simplify it by writing prototype by myself to see all problems.
At first I will write about my understanding of event bus (that can be completely wrong).
We have events like this
public class FooEvent extends GwtEvent<FooHandler> {
public static Type<FooHandler> TYPE = new Type<FooHandler>(); //as event type integer ID
//for.. hm.. probably some inner use in Event Bus
#Override public Type<FooHandler> getAssociatedType() {
return TYPE;
}
//for handling
#Override protected void dispatch(FooHandler handler) {
handler.someMethod(this);
}
}
handler interface,
public interface FooHandler extends EventHandler {
void someMethod(FooEvent event);
}
usage
eventBus.addHandler(FooEvent.TYPE, new FooHandler() {
#Override
public void someMethod(FooEvent event) {
//bla-bla
}
});
eventBus.fireEvent(new FooEvent());
Thats it. And now my prototype.
//replaced GwtEvent
interface UniGwtEvent {
}
//than, event pretty simple
public class FooEvent extends UniGwtEvent {
}
//replaced GwtEventHandler. You should not create special handler class per event!
public interface UniEventHandler<T extends UniGwtEvent> {
void handle(T event);
}
//event bus prototype(in pseudocode)
class UniEventBus {
//map. keys getted from class. as I understand, it's possible from GWT 1.5 see http://code.google.com/p/google-web-toolkit/issues/detail?id=370
public <T extends UniGwtEvent> void addListener(Class<T> event, UniEventHandler<T> handler){
map.put(event.getName(), handler);
}
public void fireEvent(UniGwtEvent event){
if(map.contains(event.getClass().getName())){
map.get(event).handle(event);
}
}
}
usage
eventBus.addListener(FooEvent.class, new UniEventHandler<FooEvent>(){
#Override
public void handle(FooEvent event) {
bla-bla
}
});
eventBus.fireEvent(new FooEvent());
I think this solution is much better since you shouldn't make unnecessary Type manipulation and create Handler Class per event. I see only one disadvantage - you should specify generic type on handler creation. But I suppose there are many other disadvantages or ever issues that makes this solution impossible. What are they?

There is no obvious advantage to using your implementation. As I read it there are two differences between yours and GWT's EventBus:
Using Strings instead of Type objects to bind event handlers to event types. This is not a meaningful difference - there's no penalty to having more types in your application and I suspect that, at runtime, Strings will use slightly more resources than Types.
Dispatching events to the appropriate handlers directly instead of delegating to the event type. I prefer GWT's approach here because it affords flexibility in how events are dispatched. One might, for example, want handlers to implement two different methods that are invoked depending on the context of the event. Take the following (trivial) example:
public class ExampleEvent extends GwtEvent<ExampleEvent.Handler> {
public interface Handler extends EventHandler {
void onExample(Integer id);
void onExample(String name);
}
private final Integer id;
private final String name;
public ExampleEvent(Integer id) {
this.id = id;
this.name = null;
}
public ExampleEvent(String name) {
this.name = name;
this.id = null;
}
public void dispatch(Handler handler) {
if (name != null) {
handler.onExample(name);
} else {
handler.onExample(id);
}
}
}
In this case delegating dispatch to the event allows us to take an action that must be performed for every handler (determining whether the event contains an id or a name) without requiring that the test be performed in every individual event handler.
I recommend using GWT's EventBus implementation - it works and it is tested.

There are other event bus implementations out there that will do a good job. I recently created a very efficient event bus (Mbassador) that I have been using in production for a while now. It's hosted on github and you are invited to take a look.
https://github.com/bennidi/mbassador
Another option would be to use google guavas event bus but it lacks some useful features (which is why I implemented my own solution)
EDIT: I created a performance and feature comparison for a selection of available event bus implementations including Guava, MBassador and some more. The results are quite interesting. Check it out here
http://codeblock.engio.net/?p=37

Related

How to listen the Change of the HashMap's specific key's Value in Java

I have to wait till the HashMap key's value change from another thread and have to continue the request processing after that.
I think the most flexible solution will be to implement the Observer pattern.
Note that build-inn interfaces Observer and Observable are deprecated since JDK version 9. Even if you are using Java 8 don't use them. The problem with them is that their names as well as the method name update() of the Observer don't tell anything to the reader of the code about the event that was triggered and what kind of actions might follow.
Ass you can see from the diagram, the subject should contain a collection of observers (or listeners).
The subject in your case should be class contains a HashMap updates of which you want to listen. Don't extend the map, wrap it with your class instead. Because if you choose to extend HashMap your code will become dependent on its implementation. And any changes in the HashMap, for instance, new methods were added or existing were improved could break your code (this topic is covered in the book "Effective Java" by Joshua Blochtake, have a look at it for more information).
So let's say we have a class OrderManager that maintains a map of Orders. This class will be a subject.
A couple of services like BillingManager, LoggingManagerand maybe some more needs to notified new order was added. These are our ***observers***. All these classes an interface, let's sayOrderAddedListenerthat defines a single methodonOrderAdded(Order order)`, that's the event we are interested in.
Note, if you need to listen to other events like removal or update, you need to define a new interface with a method responsible for that for every target event as the Interface segregation principle suggests.
OrderManager has to have a collection of observers. When a new order is being added, subject iterates through the collection of observers and invokes onOrderAdded() method on each of them.
In order to add an observer that need to listen to the order-added event OrderManager has to define a method to register it, and it's also good practice to add another one to unregister the observer that has registered to be able to remove it when you no longer need it.
Asynchronous processing
Note, that in this example, events are being processing in the same thread. If actions performed by observers are costful or might block the thread, in order to fire them asynchronously you can create a class that will implement Runnable and hold references to the observer and event (order the was added/updated), and method run() will trigger the observer. And when a new event occurs, OrderManager instead of invoking onOrderAdded() on each observer should create a new instance of that class implementing runnable by passing an observer and a new order to its constructor and then create and fire a new thread.
It's a simplified approach. But I guess it'll give an understanding of the general idea.
Implementation example
That how it might look like:
public class OrderManager {
private Map<Long, Order> orderById = new HashMap<>();
private Set<OrderAddedListener> listeners = new HashSet<>();
public void addOrder(Order order) {
// notifying observers
listeners.forEach(observer -> observer.onOrderAdded(order));
orderById.put(order.getId(), order);
}
// more methods like removeOrder(), getOrderCount() etc.
public boolean registerOrderAddedListener(OrderAddedListener listener) {
return listeners.add(listener);
}
public boolean unregisterOrderAddedListener(OrderAddedListener listener) {
return listeners.remove(listener);
}
}
public interface OrderAddedListener {
void onOrderAdded(Order order);
}
public class LoggingManager implements OrderAddedListener {
private Logger logger;
#Override
public void onOrderAdded(Order order) {
// logger.log();
System.out.println("Log message has been written");
}
}
public class BillingManager implements OrderAddedListener {
private BillingService billingService;
#Override
public void onOrderAdded(Order order) {
// billingService.sendBill(order);
System.out.println("A bill has been sent");
}
}
main() - a simple demo
public static void main(String[] args) {
OrderManager orderManager = new OrderManager();
orderManager.registerOrderAddedListener(new LoggingManager());
orderManager.registerOrderAddedListener(new BillingManager());
orderManager.addOrder(new Order());
}
Output
A log message has been written
A bill has been sent

How or why do listener interfaces work? And do interfaces have any other use rather than being a listener?

Whenever we want to create a listener, we implement a listener interface. For example, lets implement SensorEventListener.
Now we have to override the methods of this listener interface.
public void onSensorChanged(SensorEvent event);
and
public void onAccuracyChanged(Sensor sensor, int accuracy);
What I don't understand is:
Why and how these methods work when I automatically use them?
Why does onAccuracyChanged method gets called when the accuracy changes?
After all, onAccuracyChanged is just an empty method that we override because our formula (or the interface we implement) requires us to do so. If it is something magical caused by the lower levels
When and why would someone actually use an interface in his/her
self-project regardless of android?
Here is a suitable answer. Allow me to give you an example about listeners.
Listeners:
Suppose there is a class that fetches data in the background, the Worker, and another class that is interested in that data, the InterestedClass.
public class Worker extends Thread{
interface DataFetchedListener{
void onDataFetched(String data);
}
private DataFetchedListener listener;
#Override
public void run(){
String data = fetchData();
// Data fetched inform your listener so he can take action
listener.onDataFetched(data);
}
public void setDataFetchedListener(DataFetchedListener listener){
this.listener = listener;
}
private String fetchData(){
// returns the fetched data after some operations
return "Data";
}
}
public class InterestedClass implements Worker.DatafetchedListener{
#Override
public void onDataFetched(String data){
doSomethingWith(data);
}
private doSomethingWith(String data){
// just print it in the console
System.out.println("Data fetched is -> " + data);
}
}
The Worker does not care which class will manipulate its data, as long as that class follows the contract of DataFetchedListener.
Equally this means that any class is able to do something with the data (InterestedClass just prints it in the console) but Worker does not need to know which class is that, just that it implements its interface.
The main could go like this...
public class Application{
public static void main(String[] args){
InterestedClass interested = new InterestedClass();
Worker worker = new Worker();
worker.setDataFetchedListener(intereseted);
worker.start(); // Starts Worker's thread
}
}
When the Worker will fetch the data then it will notify its listener (currently the interested object) and the listener will act accordingly (interested will print the data to the console).
In computing, an interface is a shared boundary across which two or more separate components of a computer system exchange information.(Wikipedia)
You may wish to respond to some events either system events or user events. But for that you need to know when the event you wish to capture occurs and also what must be done at that time.
And for that you open a confidential EAR to listen to events. But that will not be sufficient since you need to be notified too so that you can reply according to the event. You set callbacks that will notify when an event occur. Those empty body methods we create inside an interface.
A Listener is that interface that hears and notify back through callbacks.
So how can all that be used? And how all these do interact?
First create an interface with empty bodies methods that you intend to call when an event occurs:
public interface MyListener{
void actionOneHappens(Object o);
void actionTwo();
void actionThree();
}
Create a class that handles something, for example counts:
public class MyCounter{
//create a member of type MyListener if you intend to exchange infos
private MyListener myListener;
//let's create a setter for our listener
public void setMyListener(MyListener listener)
{
this.myListener=listener;
}
MyCounter(){
}
//this method will help us count
public void startCounting()
{
new CountDownTimer(10000,1000)
{
#Override
public void onTick(long millisUntilFinished) {
//I want to notify at third second after counter launched
if(millisUntilFinished/1000==3)
{
// I notify if true :
//as someone can forget to set the listener let's test if it's not //null
if(myListener!=null){
myListener.actionThree();
}
}
}
#Override
public void onFinish() {
}
}.start();
}
}
You can then create an object of type MyCounter and know when it's at three:
MyCounter myCounter=new MyCounter();
myCounter.setMyListener(new MyListener()
{
//then override methods here
#override
void actionOneHappens(Object o){
}
#override
void actionTwo()
{}
#override
void actionThree()
{
//Add you code here
Toast.makeText(getApplicationContext(),"I'm at 3",Toast.LENGTH_LONG).show()
}
});
//start your counter
myCounter.startCounting();
And it's done!! That's how we proceed.
Interfaces have no implementation and for using them we have two options:
A class that implement them
An anonymous class
And consider this code:
interface TestInterface {
void doSomething();
}
class TestClass{
private TestInterface ti;
public TestClass(TestInterface ti){
this.ti = ti;
}
public void testActionMethod(){
ti.doSomething();
//some other codes
}
}
class OurOwnLauncherApp{
public static void main(String[] args) {
TestClass tc = new TestClass(new TestInterface() {
#Override
public void doSomething() {
System.out.println("Hi!");
}
});
tc.testActionMethod();
TestClass tc2 = new TestClass(new TestInterface() {
#Override
public void doSomething() {
System.out.println("Bye!");
}
});
tc2.testActionMethod();
}
}
In here we have:
An Interface (Just like what you asked)
A function class the uses that interface
An application somewhere that we don't know (Maybe your phone app, maybe your friends phone app, etc)
What this code does, it gives an anonymous class (which implements TestInterface) to the testActionMethod and with calling doSomething method inside testActionMethod, we invert the calling back to our own method. that's why you will see this result:
Hi!
Bye!
This is exactly a simplified version of listener interfaces and how they work
There is no magic thing. Generally, the event-listener mechanism is as follow:
For some entities, there is the possibility to listen to some events on that entity (let name this entity as event generator). So some way should exist for other entities to listen to these changes (let name these entities as listeners). Now a listener registers itself as a listener of event generator. When an event occurs on the event generator, it calls the related method of registered listeners.
As a simple example assume a button. The button may generate an event for some actions such as click. Now if a listener wants to aware when the button is clicked, it should register itself as a listener of that button. On the other hand, the button should provide a unified way of registering the listeners. This unified way is the interface. Each entity which implements the interface could register itself as a listener for click on that button:
1- Listener implements the interface
2- Listener registers itself as a listener of button (Event Generator)
3- Event Generator calls the appropriate method of all registered listeners (this method is a method of the interface).
For your case, android provides a manager which you could register a listener on some sensors by it: android.hardware.SensorManager.registerListener(). All things occurs here (which is not magic!). When you register an entity (which implemented the related interface, SensorEventListener) as a sensor listener, changes in that sensor will cause to call methods of the listener).

Android - Implementing callbacks in SDK

I'm designing SDK for Android.
As a web developer, I'm very used to and comfortable with callbacks, and as the SDK will include many async operations, I'm not sure what is the most common or "best" way to implement such a behavior on Android (or Java in general).
I've come up with a couple of options:
1) Listener interface - the developer that will use the SDK will implement a listener interface that will include all the callbacks, for example:
interface ISDKListener {
public void onA();
public void onB();
}
class SDK {
private ISDKListener _listener;
public SDK(ISDKListener listener) {
_listener = listener
}
public void a() {
// Do stuff
_listener.onA();
}
public void b() {
// Do stuff
_listener.onB();
}
}
As a web developer, using JS that looks a bit too much for me, "forcing" the user (developer) to implement all the listeners in advance, when he might no even use all of them.
2) Single listeners setters
Basically set a listener to each async method. For example:
interface ISDKCallback {
public void onComplete();
}
class SDK {
private ISDKCallback _aCb;
private ISDKCallback _bCb;
public void setAListener(ISDKCallback aCb) {
_aCb = aCb
}
public void a() {
// Do stuff
if (_aCb != null) _aCb.onComplete();
}
public void setBListener(ISDKCallback bCb) {
_bCb = bCb
}
public void b() {
// Do stuff
if (_bCb != null) _bCb.onComplete();
}
}
3) Same as #2, but separate success and errors:
interface ISDKCallback {
public void onSuccess();
public void onError(Exception e);
}
class SDK {
private ISDKCallback _aCb;
public void setAListener(ISDKCallback aCb) {
_aCb = aCb
}
public void a() {
try {
// Do stuff
if (_aCb != null) _aCb.onSuccess();
} catch (Exception e) {
if (_aCb != null) _aCb.onError(e);
}
}
}
4) Combining #1 and #3 - a complete listener with all the callbacks, but each callback will be 2 callbacks, one for success and one for errors:
interface ISDKListener {
public void onA();
public void onAError(Exception e);
public void onB();
public void onBError(Exception e);
}
class SDK {
private ISDKListener _listener;
public SDK(ISDKListener listener) {
_listener = listener
}
public void a() {
try {
// Do stuff
_listener.onA();
} catch (Exception e) {
_listener.onAError(e);
}
}
public void b() {
try {
// Do stuff
_listener.onB();
} catch (Exception e) {
_listener.onBError(e);
}
}
}
The 3rd one seems most "natural" for me, due to the separation between success and error (like the promise then and catch on JS) and setting each callback separately. Actually the most natural to me was to pass the callback when I call the method, but I did not found such implementation anywhere in Java as far as I've searched.
Which one is the most common and will be the most "natural" to most Android/Java developers? Are there any other suggestions for implementing callbacks in that platform?
EDIT:
To clarify, the callbacks are either for HTTP responses to HTTP requests or BLE communication, for example method a will send some request over BLE to a BLE peripheral, and the callback for a will be called when the peripheral returned a response (the mobile and peripheral are implementing a client-server protocol over BLE)
I'm not the biggest expert out there but if you're asking which is the most common implementation I would say numer 1. You can take a look at a lot of libraries out there, I used a lot of them myself and this is what I found to be the most used solution.
One good example would be the usage of ExoPlayer (I'm choosing it just because I'm working on it at the moment).
As you can see the activity includes an instance of the player + all the objects it needs like the BandwidthMeter and implements ExoPlayer.EventListener inheriting all the callbacks like onPlayerStateChanged.
Even the Android API itself makes use of this pattern, maybe too much. But this is another topic I guess. A lot of people finds this approach a bit confusing because you end up with a callback hell and I'm with them.
Edit
Another good example of a different approach can be found in the Google API Client (which suits your situation better).
As you can see you connect to the Client with two listener, and you have another optional listener for errors with a different interface and an additional callback.
Conclusion
I guess in the end it really depends on you: solution 1 and 2 both look good to me. Number 3 will work too but I'm not too familiar with it, maybe this is a sign that it's not a widely used pattern in Android Development.
In general, callbacks or listeners interfaces are a valid approach, but I would choose Android LiveData. It's an observational data holder which wraps your data and let others listen to your changes. In your case, I would expose LiveData with some kind of model, and the users of your sdk would then observe your return value of type LiveData for future changes in the data. Thus the users of your sdk won't have to implement nothing.
I've just wrote a blog post where I go over callbacks (as well as event bus and LiveData), describing the scenarios in which we should use one over another and the pros and cons of using one rather than the other. I think it may be useful to you:
When and why to use LiveData

Is it possible to create my own event listener list in Java containing multiple listener types?

I'm implementing a client-server system where the client is in a continuous blocking read loop listening for messages from the server. When a message is received I'd like to raise an "event" based on the type of the message, which other GUI classes may add listeners to. I'm more familiar with C# events so I am still getting used to the Java way of doing things.
There will be many message types so I will need an interface for each, call it MessageTypeAListener, MessageTypeBListener, etc., each of which will contain one handle method, which my GUI classes will implement. However, there will be be many types and instead of maintaining a list of listeners per type and having several "fire" methods I wanted to have one big listener list and a typed fire method. Then the fire method could say "only fire listeners whose type is what I specify."
So for example (pseudocode):
ListenerList.Add(MessageTypeAListener);
ListenerList.Add(MessageTypeBListener);
<T> fire(message) {
ListenerList.Where(type is T).handle(message)
}
...
fire<MessageTypeAListener>(message);
However, type erasure seems to be making this difficult. I could try casting and catching exceptions but that seems wrong. Is there a clean way of implementing this or is it just wiser to keep a separate list of listeners for every type, even though there will be tons of types?
I implemented something like this, cause I have a visceral dislike of Java's EventListenerList. First, you implement a generic Listener. I defined the listener based upon the Event it was receiving, with basically one method
interface GenericListener<T extends Event> {
public void handle(T t);
}
This saves you having to define ListenerA, ListernerB etc... Though you could do it your way with ListenerA, ListenerB, etc, all extending some base like MyListener. Both ways have plusses and minuses.
I then used a CopyOnWriteArraySet to hold all these listeners. A set is something to consider cause all too often listeners get added twice by sloppy coders. YMMV. But, effectively you have a Collection<GenericListener<T extends Event>> or a Collection<MyListener>
Now, as you've discovered, with type erasure, the Collection can only hold one type of listener. That is often a problem. Solution: Use a Map.
Since I'm basing everything upon the event, I used
Map<Class<T extends Event>, Collection<GenericListener<T extends Event>>>
based upon the class of the event, get the list of listeners who want to get that event.
Your alternative is to base it upon the class of the listener
Map<Class<T extends MyListener>, Collection<MyListener>>
There's probably some typos above...
Old-fashioned pattern approach, using Visitor pattern:
class EventA {
void accept(Visitor visitor) {
System.out.println("EventA");
}
}
class EventB {
void accept(Visitor visitor) {
System.out.println("EventB");
}
}
interface Visitor {
void visit(EventA e);
void visit(EventB e);
}
class VisitorImpl implements Visitor {
public void visit(EventA e) {
e.accept(this);
}
public void visit(EventB e) {
e.accept(this);
}
}
public class Main {
public static void main(String[] args) {
Visitor visitor = new VisitorImpl();
visitor.visit(new EventA());
}
}
More modern approach is just to have Map between classes of events, which should not derive each other, and respective handlers of these events. This way you avoid disadvantages of Visitor pattern (which is, you'll need to change all your visitor classes, at least, base of them, every time you add new Event).
And another way is to use Composite pattern:
interface Listener {
void handleEventA();
void handleEventB();
}
class ListenerOne implements Listener {
public void handleEventA() {
System.out.println("eventA");
}
public void handleEventB() {
// do nothing
}
}
class CompositeListener implements Listener {
private final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<Listener>();
void addListener(Listener l) {
if (this != l)
listeners.add(l);
}
public void handleEventA() {
for (Listener l : listeners)
l.handleEventA();
}
public void handleEventB() {
for (Listener l : listeners)
l.handleEventB();
}
}
After going through iterations of just about everyone's suggestions here, I ended up going a very slightly modified route of the standard Listener interfaces and listener lists. I started with Swing's EventListenerList, only to be disappointed with the amount of add/remove methods for dozens of message types. I realized this could not be condensed while still maintaining a single EventListenerList, so I started thinking about a separate list for each type. This makes it similar to .NET events where each event holds its own list of delegates to fire when raised. I wanted to avoid tons of add/remove methods, so I made a quick Event class that just looks like this:
public class Event<T extends EventListener> {
private List<T> listeners = new ArrayList<T>();
public void addListener(T listener) {
listeners.add(listener);
}
public void removeListener(T listener) {
listeners.remove(listener);
}
public List<T> getListeners() {
return listeners;
}
}
Then I keep several instances of this class around, each typed according to a listener, so Event<MessageTypeAListener>, etc. My classes can then call the add method to add themselves to that particular event. I would've like to be able to call a generic Raise method on the Event instance to then fire all the handlers, but I did not want them to all have to have the same "handle" method, so this was not possible. Instead, when I'm ready to fire the listeners, I just do
for (MessageTypeAListener listener : messageTypeAEvent.getListeners())
listener.onMessageTypeA(value);
I'm sure this is not a new idea and has probably been done before and in better/more robust ways, but it's working great for me and I'm happy with it. Best of all, it's simple.
Thanks for all the help.
If you only have simple events, i.e. events without data or where all events have the same data types, enum could be a way forward:
public enum Event {
A,
B,
C
}
public interface EventListener {
void handle(Event event);
}
public class EventListenerImpl implements EventListener {
#Override
public void handle(Event event) {
switch(event) {
case A:
// ...
break;
}
}
}
public class EventRegistry {
private final Map<Event, Set<EventListener>> listenerMap;
public EventRegistry() {
listenerMap = new HashMap<Event, Set<EventListener>>();
for (Event event : Event.values()) {
listenerMap.put(event, new HashSet<EventListener>());
}
}
public void registerEventListener(EventListener listener, Event event) {
Set<EventListener> listeners = listenerMap.get(event);
listeners.add(listener);
}
public void fire(Event event) {
Set<EventListener> listeners = listenerMap.get(event);
for (EventListener listener : listeners) {
listener.handle(event);
}
}
}
Comments:
The switch statement in the EventListnerImpl may be omitted if it is only registered to a single event, or if it should always act in the same way regardless of which Event it receives.
The EventRegister has stored the EventListener(s) in a map, meaning that each listener will only get the kind of Event(s) that it has subscribed to. Additionally, the EventRegister uses Sets, meaning that an EventListener will only receive the event at most once (to prevent that the listener will receive two events if someone accidentally registers the listener twice).

Implementing C#-like events in Android/Java

I'm used to programming in C#, and one thing I miss about Java is that it doesn't seem to have C#'s nice built-in event handling capabilities:
// define event signature
public delegate void SomeEventHandler();
class SomeEventGenerator {
// define subscribable event property
public event SomeEventHandler SomeEvent;
protected void OnSomeEvent() {
if (SomeEvent != null) {
SomeEvent();
}
}
}
class SomeEventClient {
public SomeEventClient(SomeEventGenerator eg) {
// subscribe
eg.SomeEvent += new SomeEventHandler(eg_SomeEvent);
// do some stuff
// unsubscribe
eg.SomeEvent -= new SomeEventHandler(eg_SomeEvent);
}
private void eg_SomeEvent() {
// handle event
}
}
What's the best way to get something similar and lightweight in Java/Android which has the ability to subscribe/unsubscribe multiple event clients and call all subscribed clients at once?
You would want to look into the concept of listeners in java. I found a very good article called "C# from a Java developers perspective" that you might want to check out.
http://www.25hoursaday.com/CsharpVsJava.html

Categories