Skip to content
Alexander V. Chernomyrdin aka chav1961 edited this page Mar 22, 2018 · 31 revisions

Pure Library Home

Release 0.0.2 coming soon

Pure Library project is a set fo useful classes I use in my own projects. To avoid duplication of JavaDoc, Wiki contains only most important descriptions of Pure library content. They are:

Java byte code assembler

Java byte code assembler is a chav1961.purelib.streams.char2byte.AsmWriter class. It extends standard java.io.Writer class functionality and can be used as usual Writer stream:

try(final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    final Writer wr = new AsmWriter(baos);) {
		
    wr.write(" 		 .package myPackage\n");
    wr.write(" 		 .import myclasses.Class1\n");
    wr.write("MyNewClass .class public extends myclasses.Class1\n");
    . . .    
    wr.write("MyNewClass .end\n");
    wr.flush();
}

After writing all the class description to the AsmWriter, target byte stream will contain valid Java class file according to Java 1.7 specifications. You can pass content of the output stream into the ClassLoader.defineClass method directly. This ability allow you to use Java byte code assembler anywhere in your programs without using specific libraries and learning specific software. Available byte code assembly instructions and preudocommands are described here.

Since 0.0.2 you can use a set of automation to simpify byte code assembler writing:

  • macro assembler (new operator .macro in the input stream)
  • chav1961.purelib.basic.AssemblerTemplateRepo class to substitute code pieces into output stream

Avoid using of java.io.PrintWriter and java.io.PrintStream with chav1961.purelib.streams.char2byte.AsmWriter, because both of these classes suppress I/O errors and you can loose any syntax exceptions in your assembler code (syntax exceptions in this byte code assembler are children of the java.io.IOException for compatibility reason).

File system interface

Functionality of the file system interface is similar to Java 1.7 file system concepts, but it extends this concept to many others implementations. Java 1.7 file system functionality can be directly accessed from this file system interface (see the second line in example below).

Important future of the file system interface is an ability to mount one file system inside another. This ability is similar to Linux mount console command fuctionality. You can build a heterogenous file system in your program anr transparently use it in your applications.

File system interface in the Pure Library contains two public entites:

  • chav1961.purelib.fsys.interfaces.FileSystemInterface interface
  • chav1961.purelib.fsys.FileSystemFactory class

FileSystemFactory class is a factory to get access to different implementation of the FileSystemInterface interface. It has a set of static methods createFileSystem(...):

    final FileSystemInterface fsi1 = FileSystemFactory.createFileSystem(URI.create("file:./mydirectory"));
    final FileSystemInterface fsi2 = FileSystemFactory.createFileSystem(URI.create("fsys:./myJar.jar"));
    final FileSystemInterface fsi3 = FileSystemFactory.createFileSystem(URI.create("xmlReadOnly:./myXML.xml"));
    final FileSystemInterface fsi4 = FileSystemFactory.createFileSystem(URI.create("rmi://myServer:12345/myRMIFileSystem"));
    final FileSystemInterface fsi5 = FileSystemFactory.createFileSystem(URI.create("csvdb:jdbc:postgresql://myServer:5432/postgres?user=myUser&passwd=myPasswd"));

Pure library contains only five implementations of the interface now:

  • file-based implemetation (URI scheme 'file')
  • Java 1.7. file-system-based implemetation (URI scheme 'fsys')
  • XML content-based implementation (URI scheme 'xmlReadOnly')
  • RMI-based implementation (URI scheme 'rmi')
  • database content-based implementation (URI scheme 'csvdb')

My project Pure Library Extensions will contain a much more implementations (SVN, Git, Amazon S3, WebDav etc) because it has no restruction of purity for it's code. Every implementation connects to JVM by standard Java SPI protocol, file name for this protocol is META-INF/services/chav1961.purelib.fsys.interfaces.FileSystemInterface.

Example of using file system see below:

    try(final FileSystemInterface fsRoot = FileSystemFactory.createFileSystem(URI.create("file:./"));
        final FileSystemInterface fsi1 = FileSystemFactory.createFileSystem(URI.create("rmi://server1:12345/myRMIFileSystem"));
        final FileSystemInterface fsi2 = FileSystemFactory.createFileSystem(URI.create("rmi://server2:12345/myRMIFileSystem"));
        final FileSystemInterface fsiTo = FileSystemFactory.createFileSystem(URI.create("rmi://server3:12345/myRMIFileSystem"))) {

        fsRoot.open("/content/fromServer1").mkDir().mount(fsi1).open("/content/fromServer2").mkDir().mount(fsi2).open("/content")
              .copy(fsiTo.open('/content').mkDir()).open("/content/fromServer1").unmount();
        fsRoot.delete().open("/content/fromServer2").unmount();
        fsRoot.delete();
    }

This example copies content from two remote servers to the target server. Pay attention, that File system interface extends Closeable interface, so you can use it in the try-with-resource.

Since 0.0.2 you can use FileSystemURLStreamHandler class to use any of the file systems in the URL-based access mechanism

SAX-styled JSON parser and deserializator

SAX-xtyle JSON parser supports quick parsing of the JSON in the XML SAX style. SAX-styled JSON parser is a chav1961.purelib.streams.JsonSaxParser class. You can pass any implementation of the chav1961.purelib.streams.interfaces.JsonSaxHandler interface to it and get events from JSON parsed (start document, end document, start name, start object, value and so on). It simpifies the JSON parsing in many cases. This is an example of 'dummy' parsing:

    final JsonSaxHandler jch = new JsonSaxHandler(){
				@Override public void startDoc() {}
				@Override public void endDoc() {}
				@Override public void startObj() {}
				@Override public void endObj() {}
				@Override public void startArr() {}
				@Override public void endArr() {}
				@Override public void startName(char[] data, int from, int len) {}
				@Override public void startName(String name) {}
				@Override public void startName(long id) {}
				@Override public void endName() {}
				@Override public void startIndex(int index) {}
				@Override public void endIndex() {}
				@Override public void value(char[] data, int from, int len) {}
				@Override public void value(String data) {}
				@Override public void value(long data) {}
				@Override public void value(double data) {}
				@Override public void value(boolean data) {}
				@Override public void value() {}
			};
    final JsonSaxParser jcp = new JsonSaxParser(jch);
		
    try(final InputStream	is = new FileInputStream("./myfile.json");
	final Reader		rdr = new InputStreamReader(is)) {
			
	jcp.parse(rdr);
    }

The Pure Library also contains a special factory class chav1961.purelib.streams.JsonSaxHandlerFactory that allow you build the chav1961.purelib.streams.interfaces.JsonSaxHandler implementation for automatic deserialization JSON content into any Java class you wish:

    final JsonSaxDeserializer<MyClass> mc = JsonSaxHandlerFactory.buildDeserializer(MyClass.class,true);
    final JsonSaxParser p = new JsonSaxParser(mc);
    .  .  .
    p.parse(...);
    final MyClass ready = mc.getInstance();
    .  .  .

When you use only public classes and fields for deserialization (true parameter in the first line of the example), JsonSaxHandlerFactory builds a special internal class (by Byte code assembler) to avoid any reflections in the parsing. This is strongly speeds up deserialization performance.

Console command manager

Console applications are not a popular theme now, but sometimes you need implementation of console command processor. The chav1961.purelib.basic.ConsoleCommandManager class allow you to simplify this task. You can deploy to it any specially annotated classes. According to it's annotations, console command manager parse console input, find appropriative class and method to process command typed, prepare parameters for it and call this method by reflection. This is a fragment from command manager JUnit test:

@ConsoleCommandPrefix("exec")
class PseudoCommandProcessor {
	public PseudoCommandProcessor(){}
	
	@ConsoleCommand(template="exec ${start} <{+${add}|-${sub}}>... ?",help="Calculate simple arithmetic expression. Use exec NNN {+|-} NNN... ? to calculate sum")
	public String addition(@ConsoleCommandParameter(name="start") int start
			 , @ConsoleCommandParameter(name="add") final  int[] additions
			 , @ConsoleCommandParameter(name="sub") final int[] substractions) {
		for (int item : additions) {
			start += item;
		}
		for (int item : substractions) {
			start -= item;
		}
		return String.valueOf(start);
	}
}
    .  .  .
    try(final ConsoleManagerInterface cmi = new ConsoleCommandManager()) {
	final PseudoCommandProcessor proc = new PseudoCommandProcessor();
			
	cmi.deploy(proc);
	.  .  .		
	Assert.assertEquals(cmi.processCmd("exec 2 + 3 - 4 + 5 ?"),"6");
	.  .  .
	cmi.undeploy(proc);
    }
    .  .  .	

Source of the console commands can be either console reader (for example, System.in), or usual string, so you can use console command manager not only for processing console input.

Pay attention, that chav1961.purelib.basic.ConsoleCommandManager implements java.lang.AutoCloseable interface, so you can use it in the try-with-resource

Internationalization

Internationalization bases on existent Java internationalization classes, but extends it with the additional options:

  • using file system interfaces to keep internationalizations
  • using annotations to automatic substitutions of the content and tool tips with the Swing components
  • supporting help system for the Swing applications
  • online change of the Locale and LocaleChangeListener to listen change locale events
  • internationalization entities hierarchy
  • using Wiki Creole markup languange in the helps and tooltips

Clone this wiki locally