I recently just upgraded my Sony Ericsson Xperia X10 phone from Android 1.6 to Android 2.1 expecting that the Mediascape application would allow me to create a playlist from the phone itself. Unfortunately I was wrong. The only way to create a playlist in Mediascape is to install a Media Go that can be downloaded from Sony PC Companion. Since I don't need another media player and I'm mostly running on Linux, installing Media Go isn't an option for me. After couple of hours googling about this issue, I found that Mediascape is able to recognize the M3U playlist file. I then went to Wikipedia to see what M3U format really is. It turns out that M3U file basically just a plain text file with some information in it and it's pretty easy to create/parse.
In order to create M3U format, there are 4 things that we need.
- Track length in seconds
- Artist name from ID3 tag
- Title name from ID3 tag
- Absolute/relative path where the audio file is located
This feature to create/read/modify the M3U format has been incorporated into my ID3Tidy application. To create a playlist in my Mediascape, all we need to do is to open the MP3 files that we wish to be included inside the playlist from /sdcard/music into the ID3Tidy application. And then create a M3U file and save it into the /sdcard/music/Whatever.m3u
Enjoy! :)
Thursday, November 18, 2010
How to Implement Groovy's File.eachLine in Java
One thing that I like from Groovy is that the closures concept. The method File.eachLine() in Groovy is indeed very useful and handy when reading a file line by line. Because of Java's lack of closures, there is a tendency to repeat the steps of reading each line of a file in every code. It is actually quite easy to implement Groovy's File.eachLine in Java.
FileFunction.java
public interface FileFunction {
public void read(String line);
}
M3UParserFileFunction.java
public class M3UParserFileFunction implements FileFunction {
private List<File> mp3Files;
private File m3uFile;
public M3UParserFileFunction(File m3uFile, List<File> mp3Files) {
this.mp3Files = mp3Files;
this.m3uFile = m3uFile;
}
@Override
public void read(String line) {
if (!line.trim().startsWith("#")) {
if (line.trim().toLowerCase().endsWith(".mp3")) {
// Try relative path first, then absolute path.
File file = new File(m3uFile.getParentFile(), line.trim());
if (file.exists()) {
mp3Files.add(file);
} else if (!file.exists()) { // Use absolute path
file = new File(line.trim());
if (file.exists()) {
mp3Files.add(file);
}
}
}
}
}
}
FileUtils.java
public class FileUtils {
private FileUtils() {
}
public static void eachLine(File file, FileFunction fileFunction) throws IOException {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
String line = "";
while ((line = br.readLine()) != null) {
fileFunction.read(line);
}
} finally {
if (br != null) {
br.close();
}
}
}
}
List<File> files = new ArrayList<File>();
FileUtils.eachLine(m3uFile, new M3UParserFileFunction(m3uFile, files));
for (File file : files) { doWhatever(file); }
Friday, November 5, 2010
Monday, September 27, 2010
How to Create an Executable WAR
Have you ever wondered how Hudson let you run a WAR file as if you run an executable JAR file? The answer is simple, i.e. embed a web container inside a WAR file and create a META-INF/MANIFEST.MF that has Main-Class attribute. For Hudson, it embeds Winstone. In this example, I'm gonna use Jetty instead.
1. Package a WAR file
3. Run it.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fredy</groupId>
<artifactId>exec-war</artifactId>
<version>0.1</version>
<packaging>war</packaging>
<name>exec-war</name>
<dependencies>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.25</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>myproject.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>exec-war</display-name>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>myproject.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
</web-app>
MyServlet.java
package myproject.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp);
}
private void process(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter pw = resp.getWriter();
try {
pw.print("<html><body><h1>Hello World</h1></body></html>");
} finally {
pw.close();
}
}
}
Main.class
package myproject;
import java.net.URL;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.webapp.WebAppContext;
public class Main {
public static void main(String[] args) throws Exception {
Server server = new Server();
Connector connector = new SelectChannelConnector();
connector.setPort(8888);
connector.setHost("127.0.0.1");
server.addConnector(connector);
URL warUrl = Main.class.getClassLoader().getResource("WEB-INF");
System.out.println(warUrl);
String warUrlString = warUrl.toExternalForm();
server.setHandler(new WebAppContext(warUrlString, "/exec-war"));
server.setStopAtShutdown(true);
server.start();
}
}
1. Package a WAR file
mvn package2. Rename the package name from JAR to WAR. The JAR still has WAR structure. The file has a JAR extension because of the maven-assembly-plugin. So, it's basically a JAR file with a WAR structure inside.
3. Run it.
java -jar exec-war.war4. Or deploy it in a web container, such as Tomcat.
My Open Source Projects
I've created two new open source projects.
FileRenamer - A small tool to do bulk renaming.
JUGen - A small tool to generate JUnit.
Do give a feedback! :)
FileRenamer - A small tool to do bulk renaming.
JUGen - A small tool to generate JUnit.
Do give a feedback! :)
Wednesday, September 22, 2010
Applying a License into Source Code
Below is a script to apply a license into source code.
ApplyLicense.groovy
validateArgs(this.args)
def projectDir = new File(this.args[0])
def licenseText = new File(this.args[1]).text
def fileExtension = this.args[2]
projectDir.eachFileRecurse { file ->
if (file.name.endsWith(fileExtension)) {
def tmpFile = new File(file.path + ".tmp")
tmpFile.text = licenseText + file.text
tmpFile.renameTo(file)
}
}
def validateArgs(def args) {
if (args.size() < 3) {
printUsage()
System.exit(1)
}
if (!new File(args[0]).isDirectory()) {
printUsage()
System.exit(1)
}
if (!new File(args[1]).isFile()) {
printUsage()
System.exit(1)
}
}
def printUsage() {
println "Usage: groovy ApplyLicense.groovy <project_dir> <license_file> <file_extension>"
}
Getting Started with JAX-RS
The example below shows how to get started with JAX-RS with Jersey (JAX-RS RI). The client side uses jQuery 1.4.2 and jQuery UI 1.8.4. The nice thing about jQuery UI 1.8.4 is that it can style the buttons according to theme specified.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>myproject</groupId>
<artifactId>jersey-app</artifactId>
<version>0.1</version>
<name>jersey-app</name>
<packaging>war</packaging>
<repositories>
<repository>
<id>maven2-repository.dev.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2/</url>
<layout>default</layout>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.25</version>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>jersey-app</display-name>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>myproject</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
The com.sun.jersey.config.property.packages tells the ServletContainer to scan which package that contains the JAX-RS classes.HelloResource.java
package myproject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
@Path("/hello/{user}")
public class HelloResource {
@Produces("text/plain")
@GET
public String getMessage(@PathParam("user") String user) {
return "Hello World, " + user;
}
}
DefaultHelloResource.java
package myproject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
@Path("/hello")
public class DefaultHelloResource {
@GET
@Produces("text/plain")
public String getMessage() {
return "Hello World";
}
}
index.jsp
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>JAX-RS with Jersey</title>
<link type="text/css" href="css/ui-lightness/jquery-ui-1.8.4.custom.css" rel="stylesheet" />
<link type="text/css" href="css/ui.jqgrid.css" rel="stylesheet" />
<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.4.custom.min.js"></script>
<script type="text/javascript">
$(function() {
$(".buttonStyle").button();
});
$(function() {
$("#button").click(function() {
$("#message").load("/jersey-app/ws/hello/" + $("#name").val());
});
});
</script>
<style type="text/css">
body {
font: 62.5% "Trebuchet MS", sans-serif;
margin: 50px;
}
</style>
</head>
<body>
<h1>Welcome to JAX-RS with Jersey Demo!</h1>
Name: <input id="name" type="text"/>
<button id="button" class="buttonStyle">Get Message</button>
<p></p>
<div id="message"/>
</body>
</html>
Subscribe to:
Comments (Atom)