Home

Description

Lightweight implementation of Socket.IO protocol applied to GWT RPC. As result - server-push in GWT! Also this library provide lightweight request processors (something like servlets) for any kind of thing that you may imagine :) It also provides SSL.

Enjoy! And bug report please.

P.S - If you want using it in prodaction - be careful, it's not tested well!.

Futures

  • Netty HTTP server for GWT RPC
  • GWT RPC requests works through Socket.IO protocol
  • Server push. Integrated to general GWT RPC
  • Authority levels for GWT RPC methods
  • Fully SSL support
  • Low level accepting to client connection
  • Very simple to use

Implemented Socket.IO transports

websocket, htmlfile, xhr-polling, jsonp-polling

I remove flashsocket (with any client-side code applied to flash) because i hate it (flash) :)

How to use

It's very simple.

Client side

First of all add this line to your *.gwt.xml

<inherits name='net.gnisio.Gnisio'/>

Create regular "...Service" and "...ServiceAsync" but extends SocketIOService and SocketIOServiceAsync.

@RemoteServiceRelativePath("socket.io")
public interface GreetingService extends SocketIOService {
	
	public enum PushEvent implements PushEventType {
		@PushClass(String.class)  TEST_EVENT,
		@PushClass(Integer.class) TEST_EVENT_1
	}
	
        @AuthorityLevel(0)
	String greetServer(String name) throws IllegalArgumentException;

        @AuthorityLevel(1)
	String forAuthorizedUsers();
}

public interface GreetingServiceAsync extends SocketIOServiceAsync {
	
	void greetServer(String input, AsyncCallback<String> callback)
			throws IllegalArgumentException;

	void forAuthorizedUsers(AsyncCallback<String> callback);
}

As you can see, GreetingService interface contains some Enum implementing PushEventType. This enum is events, that you want push on server side and handle on client side. This enum MUST be named PushEvent and MUST implements PushEventType. Any event MUST be annotated with @PushClass with any serializable Class value. It needs for validating received data from server.

For handling any event you need create Service as you do it with general GWT services

private final GreetingServiceAsync greetingService = GWT
			.create(GreetingService.class);
	
public void onModuleLoad() {
	greetingService.handleEvent(PushEvent.TEST_EVENT, new AsyncCallback<String>() {
		@Override
		public void onFailure(Throwable caught) {	
		}

		@Override
		public void onSuccess(String result) {
			Window.alert(result);
		}
	});
}

... and for handling event, just add handler by invoking handleEvent method of created service. Very simple!

Server side

First of all you need create class extending AbstractGnisioServer, Something like this...

public class ExampleChat extends AbstractGnisioServer {

	public static void main(String[] args) {
		try {
			new ExampleChat().start(3001);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	protected void createRequestProcessors(RequestProcessorsCollection requestProcessors) throws Exception {
		requestProcessors.addProcessor(new StaticContentProcessor("./war"), "/*");
		requestProcessors.addProcessor(new SocketIOScriptProcessor(), "/socket.io/socket.io.js");
	}

	@Override
	protected AbstractRemoteService createRemoteService(SessionsStorage sessionsStorage, ClientsStorage clientsStorage) {
		return new GreetingServiceImpl("./war");
	}

}

It's entry point of your server. You must implement createRequestProcessors and createRemoteService methods. First method is similar as you adding servlets for Jetty for different URI patterns. Second method must return your GWT RPC service. This service is...

public class GreetingServiceImpl extends AbstractRemoteService implements
		GreetingService {

	public GreetingServiceImpl(String gwtAppLocation) {
		super(gwtAppLocation);
	}

	public String greetServer(String input) throws IllegalArgumentException {
		// Verify that the input is valid. 
		if (!FieldVerifier.isValidName(input)) {
			// If the input is not valid, throw an IllegalArgumentException back to
			// the client.
			throw new IllegalArgumentException(
					"Name must be at least 4 characters long");
		}
		
		pushEvent(PushEvent.TEST_EVENT, "Yahooo!!! It works!", "/");

                // Set next authority level for the session
                // After this user can invoke "forAuthorizedUsers" method
		getSession().setAuthorityLevel(1);
		return "Hello, " + input + "!<br><br>I am running ";
	}

	public String forAuthorizedUsers() {
		return "I'm authorized user!";
	}

	@Override
	public void onClientConnected() {
		addSubscriber("/");
	}

	@Override
	public void onClientDisconnected() {
		removeSubscriber();
	}
	
}

Your service must extends AbstractRemoteService and implement your service interface, as you do it in general GWT RPC remote service. But you must implement two methods: onClientConnected and onClientDisconnected. This methods invoked when client connected to server and disconnected from server. In this methods you can subscribe connected client for any nodes of events. For pushing some event for all (expect current client) connected clients and subscribed for some node, you just need invoke pushEvent with some event type, result object and node. Simple again!

Updated

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.