Leonardo Garcia Fischer

LinkedIn Facebook Twitter Feeds

Introducing JSS: Java Simple Services

10Jul'12

Written by Leonardo Fischer

A few weeks ago, I needed to implement a service. Or a daemon. Or whatever you call a process that you start, and it runs in background until you call it to stop. I found the Java Service Wrapper, but I didn’t like it: it has several OS dependent distributions, and a documentation that you take some time to learn. Other options include some forums recommending some scripts that depend on the operating system that allows you to run a java application in background. No one seems as easy as I thought that it could be.

So I decided to take the joy of writing my own service wrapper. I called it Java Simple Services. I focused on making it simple, small and only dependent on the JDK. The result is a small set of classes that manages the service for the user, making it relatively easy to start a background process. First, I’ll present how to use it. If you’re interested on how it works, just keep reading.

The Clock Application Example

I like the ‘learn by example’ approach, so I will present a very simple clock application. When started, it will run “forever”, or until you give it a signal to stop. At each loop, it will update the last time read. You can think of it as a much more complex process, such as a web server or a database system that should run in background mode. It will serve as an example for the service that I will build using Java Simple Services.

package com.leonardofischer.jss.test;
import java.util.Date;
public class ClockApp {
    public boolean keepRunning = true;
    public String date = "Not executed yet";
    public void run() {
        try {
            while (keepRunning) {
                date = (new Date()).toString();
                System.out.println(date);
                Thread.sleep(1000);
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        ClockApp clock = new ClockApp();
        clock.run();
    }
}

The Service Class: Creating the Clock Service

I tried to build an API as simple as possible to create services. After some work, I got an API design that requires you to implement only one abstract class and that is it.

In the Java Simple Services, you need to extend the Service class. Although it has several methods you can override, you only need to know three methods: start(String args[]), stop(String args[]) and parseArgs(String args[]). You can think this way:

So, here is the code to wrap our clock application in a service:

package com.leonardofischer.jss.test;
import com.leonardofischer.jss.Service;
public class ClockService extends Service {
    ClockApp clock;
    public void start(String[] args) {
        clock = new ClockApp();
        clock.run();
    }

    public void stop(String[] args) {
        clock.keepRunning = false;
    }

    public static void main(String[] args) {
        ClockService clockService = new ClockService();
        clockService.parseArgs(args);
    }
}

Using Java Simple Services and the code above, you have an application that runs in background, can be started, and stopped and so on… Let’s run it:

$> java com.leonardofischer.jss.test.ClockService
Usage: java com.leonardofischer.jss.test.ClockService {start|stop|restart|sta
tus}
$> java com.leonardofischer.jss.test.ClockService start
The service started
$> java com.leonardofischer.jss.test.ClockService start
The service is already running, or another process is using the port 6400.
$> java com.leonardofischer.jss.test.ClockService status
STATUS: the service is running
$> java com.leonardofischer.jss.test.ClockService restart
The service stoped
The service started
$> java com.leonardofischer.jss.test.ClockService status
STATUS: the service is running
$> java com.leonardofischer.jss.test.ClockService stop
The service stoped
$> java com.leonardofischer.jss.test.ClockService stop
The service is not running
$>

As you can see, it is very easy to execute, get status and stop the ClockApp in a background process. The commands above are already built into JSS, so all the code you needed was the new ClockService class. But how you can change those generic default messages? How to return the current time using the status command? All that can be changed using service configuration.

Service Customization

The code above may be too simple for what you need, so I developed several methods in the service class that, if you override, should allow you to customize your service. I’ll present some methods, but please give a look at the class Documentation, so you can know exactly what you can do here.

public class ClockService extends Service {
    // same code as above, plus these methods
    public String status(String[] args) {
        return clock.date;
    }
    public void onServiceNotRunning() {
        printErrorMessage("The ClockService is not running, "+
                "please start it with the 'iniciar' command");
    }
    // new version of the main, with some customization
    public static void main(String[] args) {
        ClockService clockService = new ClockService();
        // 'iniciar' is the portuguese word for 'start'
        clockService.setStartCommand("iniciar");
        // Go to 'How Java Simple Services Work' if you want to know
        // why setting a port here
        clockService.getServiceController().setPort(9876);
        clockService.parseArgs(args);
    }
}

And if we run again those commands…

$> java com.leonardofischer.jss.test.ClockService
Usage: java com.leonardofischer.jss.test.ClockService {iniciar|stop|restart|s
tatus}
$> java com.leonardofischer.jss.test.ClockService start
Usage: java com.leonardofischer.jss.test.ClockService {iniciar|stop|restart|s
tatus}
$> java com.leonardofischer.jss.test.ClockService iniciar
The service started
$> java com.leonardofischer.jss.test.ClockService iniciar
The service is already running, or another process is using the port 9876.
$> java com.leonardofischer.jss.test.ClockService status
Wed Jul 11 21:53:51 BRT 2012
$> java com.leonardofischer.jss.test.ClockService restart
The service stoped
The service started
$> java com.leonardofischer.jss.test.ClockService status
Wed Jul 11 21:54:19 BRT 2012
$> java com.leonardofischer.jss.test.ClockService stop
The service stoped
$> java com.leonardofischer.jss.test.ClockService stop
The ClockService is not running, please start it with the 'iniciar' command
$>

I did not use here all the possible customization. I only wanted to show you some examples, such as returning the last read time with the status command, changing the command string used to start the service and change the error message if the service is not running.

Also, there is a ServiceController class that helps on the service execution. There are some customization points here too, but they are more related to the process that will be executed in background. Read carefully the documentation before use these methods, ok?

How Java Simple Services Work

This is the advanced topic on Java Simple Services, so not everyone needs to read from now on to use it. But I invite you to continue reading.

First of all, your service will run in a different process than the one that you executed it with the start command line parameter. If you use the ‘run’ parameter, then it will run in this process, but with start, another process will be started with the ‘run’ parameter, and the process that you started will finish normally. The configuration of the ServiceController class serves to customize how the JVM will be executed here.

When you execute the run parameter, the ServiceController also creates a thread that listens for future commands. It uses the Java Socket API, and that is why you can set a port to listen to. This socket will be opened until you return from your start(String args[]) method. Note that this thread will be blocked by the socket waiting for a connection, so it will not take any processor time until you try to connect to the service.

If you run a command such as stop, status or restart, the process that executes this command will connect to the service through the socket. Thus, you need to use the same port that you used to run your service, or you will not be able to connect to it. When the running server receives a command through the socket, it understands it (as well as the command line parameters from the command line) and calls the corresponding service method.

That’s it!

That’s all folks. I hope that Java Simple Services can be as helpful to you as it was for me. I am releasing the full source code, and I invite you to submit any bug fix or feature that you developed for it. Or just leave a comment with your thoughts about it.

If you are interested in download Java Simple Services go to Git Hub, I’m pushing updates there. You can also download the latest build, so you can try it.

Update 1: I did several code updates days after publishing this post, so I did updated the output shown as well as some complement text to it.

Tags:

No comments yet

Android SDK: Using the Scroller object to create a page flip interaction

23Oct'11

Written by Leonardo Fischer

This weekend I decided to play with the Android SDK. I decided to implement an app that uses the basic sweep gesture: you can touch the buttons, but you can drag to change the current page smoothly, or use a gesture to flip between views. The one from the Home screen of most Androids phones and iPhones. There are several solutions on the net, but I thought that it will be great if I developed one on my own. And it was ツ

So, this is my solution, the PageFlipper class. I extended the ViewGroup, so each child you add to my class will be a page on the final view. I use the onInterceptTouchEvent method to check if the user wants to drag/flip the screen or just want to click on a button on it. If I understand the user’s intent to change the page, the method returns true, and the motion of the screen is divided between the onTouchEvent and the computeScroll methods.

My solution uses a very simple State Machine. Take a look at it. I will explain the code based on it.

1) Firstly, the user touches the screen. In the onInterceptTouchEvent, I capture the initial coordinates of the touch, and changes to the state ST_WAITING. The VelocityTracker is initialized here to compute the velocity that the user moves his finger on the screen. Note that I return false from here because I want to watch the MotionEvent, but I still want to let the target child receive the event.

if (action == MotionEvent.ACTION_DOWN && getState() == ST_IDLE) {
    if (mVTracker != null) {
        mVTracker.recycle();
    }
    mVTracker = VelocityTracker.obtain();
    mVTracker.addMovement(event);
    setState(ST_WATCHING);
    mLastX = mFirstX = (int) event.getX();
    mFirstY = (int) event.getY();
    return false;
}

2) The user leaves his finger from the screen. Just go back to the ST_IDLE state, and releases the VelocityTracker object.

if (action == MotionEvent.ACTION_UP || 
        action == MotionEvent.ACTION_CANCEL) {
    setState(ST_IDLE);
    mVTracker.recycle();
    mVTracker = null;
}
return false;

3) Now the things are getting interesting. The user’s finger moved slowly across the screen. What we do here is check if he moved long enough on the horizontal axis to assume that the screen should be moved. If it is true, changes to the ST_DRAGGING state. By returning true here, the current and the next MotionEvents will be delivered direct to the onTouchEvent of my class. The ST_IGNORING is just to avoid interaction with the PageFlipper while the user is interacting with, let’s say, a list in one of the pages.

if (action == MotionEvent.ACTION_MOVE && getState() == ST_WATCHING) {
    int deltaX = Math.abs(mFirstX - (int) event.getX());
    int deltaY = Math.abs(mFirstY - (int) event.getY());
    if (deltaX > mTouchSlop && deltaY < mTouchSlop) {
        setState(ST_DRAGGING);
        return true;
    }
    if (deltaX < mTouchSlop && deltaY > mTouchSlop) {
        setState(ST_IGNORING);
        return false;
    }
}

4) While the user is moving his finger on the screen, I scroll the view. Doing this way the user can actually drag the views on the screen.

if (getState() == ST_DRAGGING && action == MotionEvent.ACTION_MOVE) {
    int deltaX = mLastX - (int) event.getX();
    scrollBy(deltaX, 0);
    mLastX = (int) event.getX();
}

5 and 6) When the user stops touching the screen, the state changes to ST_ANIMATING. Here are several things to do. First, I use the VelocityTracker to compute the speed that the user moved his finger. If it is greater than a minimum speed, the animation will scroll the view to the next child on the left or right. If the user moved his finger slowly, but for more than 50% of the screen, it is moved to the left or right too. If not, then move the view to the correct position back again.

if (getState() == ST_DRAGGING && (action == MotionEvent.ACTION_UP
        || action == MotionEvent.ACTION_CANCEL)) {
    setState(ST_ANIMATING);
    mVTracker.computeCurrentVelocity(1000);
    float velocity = mVTracker.getXVelocity();
    final int width = getWidth();
    final int delta = mLastX - mFirstX;
    final boolean fling = Math.abs(velocity) > mFlingSlop;
    final boolean moveToNextScreen = Math.abs(delta) > (width / 2);
    if (fling || moveToNextScreen) {
        int motion = (delta > 0 ? -1 : 1) * (width - Math.abs(delta));
        mScroller.startScroll(getScrollX(), getScrollY(), motion, 0);
    } else {
        mScroller.startScroll(getScrollX(), getScrollY(), delta,  0);
    }
    invalidate();
    mLastX = mFirstX = mFirstY = -1;
    mVTracker.recycle();
    mVTracker = null;
}

Note that I call the invalidate() method on the end. This will force the view to redraw itself. But before that, the SDK will call the computeScroll() method, which is the key to animate the scroll of our view. Note that the methods scrollTo() and scrollBy() just move the view at once to the specified position. So, the Scroller object will help us to move just a little bit at a time, to give the feeling of an animation.

7 and 8) Finishing the main code, our computeScroll() will be called after the call to invalidate() that we did before. The computeScrollOffset() method will return true until the scroll has been completed. So we move a little bit again the view, and call invalidate() again. When the scroller is finished, go back to the state ST_IDLE.

public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        invalidate();
    } else {
        if (getState() == ST_ANIMATING && mScroller.isFinished())
            setState(ST_IDLE);
        super.computeScroll();
    }
}

There are some points that I didn’t solved in this code. One is that the view gets lost if you try to sweep to the left of the first view or the right of the last view. Also, if you add a child view that doesn’t receive touchEvents (such as a TextView), the MotionEvents are not working as I would expect. You need to call setClickable(true) in these cases.

Please, download the full source code of the PageFlipper class and an running example. I hope that you can use it for your projects. And, if you use it or find a bug, please leave a comment bellow ツ

Tags:

3 comments

css.php