Sunday, January 6, 2013

Java Telnet Server

This Java server  applications is to support "telnet" like connections. It supports multiple concurrent connections.

Client we can use the classic telnet client like CLI. Telnet Server will responds to basic commands like pwd, cd, mkdir, ls, ls -l, rm. This is portable across platforms.

If this is given as a task. How to implement this?
To implement this we can use of Runtime executor/Process Builder.  But the challenge is Without using these how to develop a telnet server ?

We can make use of Java7 NIO to implement this across platforms.

Little about Java 7 NIO

Path class in Java 7 is similar to File class in Java 6.
The Java I/O File API, as it was originally created, was not written to be extended. Many of the methods do not throw exceptions even when an error is encountered leaving developers wondering what's happening. The following code in Java 6.0 will not throw any exception even if the file is not found in the filesystem.

 File f = new File("c:\\test.txt");
 f.delete();
Shown below is the code in Java 7.0 using Path class but it throws exception when file is not found.
  
 Path fp = Paths.get("c:\\test.txt");   // get Path object
 Files.delete(fp);  // delete file represented by path object
output
======
Exception in thread "main" java.nio.file.NoSuchFileException: c:\test.txt

There is much more about Java 7 NIO2. We will discuss few in this blog.

Access below link for complete source code.
Below class is used to start a socket for concurrent users.
Java FixedThreadPool executor is used for multiple concurrent requests. For each request a  WorkerThread.java is invoked.
For each socket opened through CLI a dedicated WorkerThread is spanned.
Below is the WorkerThread.java.
WorkerThread  has run method which is waiting for input command from CLI.   If the input command is "exit" prompt will exit the console otherwise input command is parsed to return output. Input command can be cd, rm, del ..etc.  output for the command is returned based on OS and command type.

WorkerThread has a class variable CURRENT_DIRECTORY. This is a string which is used to store current direcotry. User can play around with path. he can naivate to different paths in his directory using cd .., cd <dir>. To store his current path we use this variable.

Below method frm WorkerThread java class will parse command based on OS. Based on OS respective method is called. For Unix below method is called "parseUnixCmdSwitch() "is  invoked.
Below is the code to find current OS.
  
Java 7 NIO few basic classes and their use.
The following attribute views are available in the new Java 7 NIO.2 API,
AclFileAttributeView and AclEntry - Supports reading or updating a file's Access Control Lists (ACL). The NFSv4 ACL model is supported. Any ACL model, such as the Windows ACL model, that has a well-defined mapping to the NFSv4 model might also be supported.
The AclFileAttributeView allows you to get and set the ACL and file-owner attributes of a particular file. Its getAcl() method returns a List of AclEntry objects, one for each permission set on the file. Its setAcl(List<AclEntry>) method allows you to modify that access list. This attribute view is only available for Microsoft Windows systems.
BasicFileAttributeView and BasicFileAttributes - Provides a view of basic attributes that are required to be supported by all file system implementations.
FileVisitor Java 7 NIO.2 API allows you to implement scenario in which you want to traverse a directory tree recursively, stopping at each file and directory under that tree and having your own callback methods invoked for each entry found. These callback methods are called while visiting files.
  • FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) is called before the entries in that directory are visited. It returns one of the FileVisitResult's enum values to tell the file visitor API what to do next.
  • FileVisitResult visitFile(T file, BasicFileAttributes attrs) is called when a file in the current directory is being visited. The attributes for this file are passed into the second parameter.
  • FileVisitResult visitFileFailed(T file, IOException exc) is called when the visit to a file has failed. The second parameter specifies the exception that caused the visit to fail. This method is invoked if the file's attributes could not be read, the file is a directory that could not be opened, and other reasons.
  • FileVisitResult postVisitDirectory(T dir, IOException exc) is called after the visit to a directory and all its subdirectories has completed. The exception parameter is null when the directory visit has been successful, or it contains the exception that caused the directory visit to end prematurely.
 PosixFileAttributeView and PosixFileAttributes - Extends the basic attribute view with attributes supported on file systems that support the POSIX family of standards, such as UNIX. These attributes include file owner, group owner, and the nine related access permissions.
This view class, available on UNIX systems only, allows you to get and set attributes specific to POSIX (Portable Operating System Interface). Its readAttributes() method returns a PosixFileAttributes instance containing details of the owner, group owner, and file permissions for this file (those you would normally set using the UNIX chmod command). The view also provides setOwner(UserPrincipal), setGroup(GroupPrincipal), and setPermissions(Set<PosixFilePermission>) methods to modify these attributes.

Now we will go through each  command  like cd, pwd  and how java 7 NIO is used to respond to these commands.

Below code is basic example to get BasicFileAttributes.

Unix LS command:

$ ls -l
-rw-r----- 1 naresh team-dev 9275204 Jun 13 15:27 mthesaur.txt.gz

Field 1 - File Permissions:
Field 2 - Number of links: Second field specifies the number of links for that file. In this example,  1 indicates only one link to  this file.
Field 3 - Owner: Third field specifies owner of the file. In this example, this file is owned by username ‘naresh’.
Field 4 - Group: Fourth field specifies the group of the file. In this example, this file belongs to ”team-dev’ group.
Field 5 - Size: Fifth field specifies the size of file. In this example, ’9275204′ indicates the file size.
Field 6 - Last modified date & time: Sixth field specifies the date and time of the last modification of the file.
               In this example,  ‘Jun 13 15:27′ specifies the last modification time of the file.
Field 7 - File name: The last field is the name of the file. In this example, the file name is mthesaur.txt.gz.

To get permissions we can use below code.

Path p = fs.getPath("/home/nareshk/backup/abc.xml");
PosixFileAttributes attr = Files.readAttributes(path, PosixFileAttributes.class);
String permissions = PosixFilePermissions.toString(attr.permissions());



From the above code. Posix is used to get file permissions, Owner, group, lastModifiedTime, noOfLinks.

RM (remove command)
The Java 7 NIO library allows you to walk a file tree and visit each file in the tree. You do this by implementing a FileVisitor and then calling Files.walkFileTree using the visitor. The visitor has four methods as described at the begining.

Recursively Delete all Files in a Directory:The following code shows how you can recursively delete a directory by walking the file tree. It does not follow symbolic links. I have overridden the visitFile and postVisitDirectory methods in SimpleFileVisitor so that when a file is visited, it is deleted and after all the files in the directory have been visited, the directory is deleted.

Code in the bitbucket has more commands described.

No comments:

Post a Comment