From 30881a5975459400ac6e208cd28d51b6855d1d95 Mon Sep 17 00:00:00 2001
From: HongKee Moon <hkmoon@me.com>
Date: Tue, 6 Jan 2015 14:10:24 +0100
Subject: [PATCH] Handle multiple datasets with different contexts and XML file
 provided through http

For example, if BigDataViewer uses http://localhost:8080/HisYFP-SPIM, it will process the xml file directly and access the remote BigDataServer.
---
 src/main/java/bdv/server/BigDataServer.java  | 120 ++-------------
 src/main/java/bdv/server/CellHandler.java    | 153 +++++++++++++++++++
 src/main/java/bdv/server/DataSetHandler.java |  46 ++++++
 3 files changed, 211 insertions(+), 108 deletions(-)
 create mode 100644 src/main/java/bdv/server/CellHandler.java
 create mode 100644 src/main/java/bdv/server/DataSetHandler.java

diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java
index 992c7fb..d9faf64 100644
--- a/src/main/java/bdv/server/BigDataServer.java
+++ b/src/main/java/bdv/server/BigDataServer.java
@@ -1,125 +1,29 @@
 package bdv.server;
 
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import mpicbg.spim.data.SpimDataException;
-import net.imglib2.img.basictypeaccess.volatiles.array.VolatileShortArray;
-import net.imglib2.realtransform.AffineTransform3D;
-
-import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AbstractHandler;
 
-import bdv.img.cache.CacheHints;
-import bdv.img.cache.LoadingStrategy;
-import bdv.img.cache.VolatileCell;
-import bdv.img.cache.VolatileGlobalCellCache;
-import bdv.img.hdf5.Hdf5ImageLoader;
-import bdv.img.remote.AffineTransform3DJsonSerializer;
-import bdv.img.remote.RemoteImageLoaderMetaData;
-import bdv.spimdata.SequenceDescriptionMinimal;
-import bdv.spimdata.SpimDataMinimal;
-import bdv.spimdata.XmlIoSpimDataMinimal;
-
-import com.google.gson.GsonBuilder;
+import java.util.HashMap;
 
 public class BigDataServer
 {
+	static HashMap< String, String > dataSet = new HashMap<>();
+
 	public static void main( final String[] args ) throws Exception
 	{
-		final String fn = args.length > 0 ? args[ 0 ] : "/Users/pietzsch/Desktop/data/fibsem.xml";
+		final String fn = args.length > 0 ? args[ 0 ] : "/Users/moon/Projects/git-projects/BigDataViewer/data/HisYFP-SPIM.xml";
+
+		dataSet.put( "HisYFP-SPIM", fn );
+
 		final int port = args.length > 1 ? Integer.parseInt( args[ 1 ] ) : 8080;
 		System.setProperty( "org.eclipse.jetty.util.log.class", "org.eclipse.jetty.util.log.StdErrLog" );
 		final Server server = new Server( port );
-		server.setHandler( new CellHandler( fn ) );
-		server.start();
-		server.join();
-	}
 
-	static class CellHandler extends AbstractHandler
-	{
-		private final VolatileGlobalCellCache< VolatileShortArray > cache;
-
-		private final String metadataJson;
-
-		private final RemoteImageLoaderMetaData metadata;
-
-		private final CacheHints cacheHints;
-
-		public CellHandler( final String xmlFilename ) throws SpimDataException
-		{
-			final SpimDataMinimal spimData = new XmlIoSpimDataMinimal().load( xmlFilename );
-			final SequenceDescriptionMinimal seq = spimData.getSequenceDescription();
-			final Hdf5ImageLoader imgLoader = ( Hdf5ImageLoader ) seq.getImgLoader();
-			cache = imgLoader.getCache();
-			metadata = new RemoteImageLoaderMetaData( imgLoader, seq );
+		String baseURL = "http://" + server.getURI().getHost() + ":" + port + "/";
 
-			final GsonBuilder gsonBuilder = new GsonBuilder();
-			gsonBuilder.registerTypeAdapter( AffineTransform3D.class, new AffineTransform3DJsonSerializer() );
-			gsonBuilder.enableComplexMapKeySerialization();
-			metadataJson = gsonBuilder.create().toJson( metadata );
-			cacheHints = new CacheHints( LoadingStrategy.BLOCKING, 0, false );
-		}
+//		System.out.println(baseURL);
 
-		@Override
-		public void handle( final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException
-		{
-			final String cellString = request.getParameter( "p" );
-			if ( cellString == null )
-				return;
-			final String[] parts = cellString.split( "/" );
-			if ( parts[ 0 ].equals( "cell" ) )
-			{
-				final int index = Integer.parseInt( parts[ 1 ] );
-				final int timepoint = Integer.parseInt( parts[ 2 ] );
-				final int setup = Integer.parseInt( parts[ 3 ] );
-				final int level = Integer.parseInt( parts[ 4 ] );
-				VolatileCell< VolatileShortArray > cell = cache.getGlobalIfCached( timepoint, setup, level, index, cacheHints );
-				if ( cell == null )
-				{
-					final int[] cellDims = new int[] {
-							Integer.parseInt( parts[ 5 ] ),
-							Integer.parseInt( parts[ 6 ] ),
-							Integer.parseInt( parts[ 7 ] ) };
-					final long[] cellMin = new long[] {
-							Long.parseLong( parts[ 8 ] ),
-							Long.parseLong( parts[ 9 ] ),
-							Long.parseLong( parts[ 10 ] ) };
-					cell = cache.createGlobal( cellDims, cellMin, timepoint, setup, level, index, cacheHints );
-				}
-
-				final short[] data = cell.getData().getCurrentStorageArray();
-				final byte[] buf = new byte[ 2 * data.length ];
-				for ( int i = 0, j = 0; i < data.length; i++ )
-				{
-					final short s = data[ i ];
-					buf[ j++ ] = ( byte ) ( ( s >> 8 ) & 0xff );
-					buf[ j++ ] = ( byte ) ( s & 0xff );
-				}
-
-				response.setContentType( "application/octet-stream" );
-				response.setContentLength( buf.length );
-				response.setStatus( HttpServletResponse.SC_OK );
-				baseRequest.setHandled( true );
-				final OutputStream os = response.getOutputStream();
-				os.write( buf );
-				os.close();
-			}
-			else if ( parts[ 0 ].equals( "init" ) )
-			{
-				response.setContentType( "application/octet-stream" );
-				response.setStatus( HttpServletResponse.SC_OK );
-				baseRequest.setHandled( true );
-				final PrintWriter ow = response.getWriter();
-				ow.write( metadataJson );
-				ow.close();
-			}
-		}
+		server.setHandler( new DataSetHandler( baseURL, dataSet ) );
+		server.start();
+		server.join();
 	}
 }
diff --git a/src/main/java/bdv/server/CellHandler.java b/src/main/java/bdv/server/CellHandler.java
new file mode 100644
index 0000000..db215cc
--- /dev/null
+++ b/src/main/java/bdv/server/CellHandler.java
@@ -0,0 +1,153 @@
+package bdv.server;
+
+import bdv.img.cache.CacheHints;
+import bdv.img.cache.LoadingStrategy;
+import bdv.img.cache.VolatileCell;
+import bdv.img.cache.VolatileGlobalCellCache;
+import bdv.img.hdf5.Hdf5ImageLoader;
+import bdv.img.remote.AffineTransform3DJsonSerializer;
+import bdv.img.remote.RemoteImageLoaderMetaData;
+import bdv.spimdata.SequenceDescriptionMinimal;
+import bdv.spimdata.SpimDataMinimal;
+import bdv.spimdata.XmlIoSpimDataMinimal;
+import com.google.gson.GsonBuilder;
+import mpicbg.spim.data.SpimDataException;
+import net.imglib2.img.basictypeaccess.volatiles.array.VolatileShortArray;
+import net.imglib2.realtransform.AffineTransform3D;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.input.SAXBuilder;
+import org.jdom2.output.XMLOutputter;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+public class CellHandler extends AbstractHandler
+{
+	private final VolatileGlobalCellCache< VolatileShortArray > cache;
+
+	private final String metadataJson;
+
+	private final RemoteImageLoaderMetaData metadata;
+
+	private final CacheHints cacheHints;
+
+	private final String xmlFile;
+
+	private final String dataSetURL;
+
+	public CellHandler( final String baseUrl, final String xmlFilename ) throws SpimDataException
+	{
+		final SpimDataMinimal spimData = new XmlIoSpimDataMinimal().load( xmlFilename );
+		final SequenceDescriptionMinimal seq = spimData.getSequenceDescription();
+		final Hdf5ImageLoader imgLoader = ( Hdf5ImageLoader ) seq.getImgLoader();
+		cache = imgLoader.getCache();
+		metadata = new RemoteImageLoaderMetaData( imgLoader, seq );
+
+		final GsonBuilder gsonBuilder = new GsonBuilder();
+		gsonBuilder.registerTypeAdapter( AffineTransform3D.class, new AffineTransform3DJsonSerializer() );
+		gsonBuilder.enableComplexMapKeySerialization();
+		metadataJson = gsonBuilder.create().toJson( metadata );
+		cacheHints = new CacheHints( LoadingStrategy.BLOCKING, 0, false );
+
+		// dataSetURL property is used for providing the XML file by replace SequenceDescription>ImageLoader>baseUrl
+		xmlFile = xmlFilename;
+		dataSetURL = baseUrl;
+	}
+
+	@Override
+	public void handle( final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException
+	{
+		final String cellString = request.getParameter( "p" );
+		if ( cellString == null )
+			return;
+		final String[] parts = cellString.split( "/" );
+		if ( parts[ 0 ].equals( "cell" ) )
+		{
+			final int index = Integer.parseInt( parts[ 1 ] );
+			final int timepoint = Integer.parseInt( parts[ 2 ] );
+			final int setup = Integer.parseInt( parts[ 3 ] );
+			final int level = Integer.parseInt( parts[ 4 ] );
+			VolatileCell< VolatileShortArray > cell = cache.getGlobalIfCached( timepoint, setup, level, index, cacheHints );
+			if ( cell == null )
+			{
+				final int[] cellDims = new int[] {
+						Integer.parseInt( parts[ 5 ] ),
+						Integer.parseInt( parts[ 6 ] ),
+						Integer.parseInt( parts[ 7 ] ) };
+				final long[] cellMin = new long[] {
+						Long.parseLong( parts[ 8 ] ),
+						Long.parseLong( parts[ 9 ] ),
+						Long.parseLong( parts[ 10 ] ) };
+				cell = cache.createGlobal( cellDims, cellMin, timepoint, setup, level, index, cacheHints );
+			}
+
+			final short[] data = cell.getData().getCurrentStorageArray();
+			final byte[] buf = new byte[ 2 * data.length ];
+			for ( int i = 0, j = 0; i < data.length; i++ )
+			{
+				final short s = data[ i ];
+				buf[ j++ ] = ( byte ) ( ( s >> 8 ) & 0xff );
+				buf[ j++ ] = ( byte ) ( s & 0xff );
+			}
+
+			response.setContentType( "application/octet-stream" );
+			response.setContentLength( buf.length );
+			response.setStatus( HttpServletResponse.SC_OK );
+			baseRequest.setHandled( true );
+			final OutputStream os = response.getOutputStream();
+			os.write( buf );
+			os.close();
+		}
+		else if ( parts[ 0 ].equals( "init" ) )
+		{
+			response.setContentType( "application/octet-stream" );
+			response.setStatus( HttpServletResponse.SC_OK );
+			baseRequest.setHandled( true );
+			final PrintWriter ow = response.getWriter();
+			ow.write( metadataJson );
+			ow.close();
+		}
+	}
+
+	public void provideXML( final Request baseRequest, final HttpServletResponse response ) throws IOException, ServletException
+	{
+		final SAXBuilder sax = new SAXBuilder();
+		Document doc;
+		try
+		{
+			doc = sax.build( xmlFile );
+		}
+		catch ( final Exception e )
+		{
+			throw new ServletException( e );
+		}
+		final Element root = doc.getRootElement();
+		final Element SequenceDescription = root.getChild( "SequenceDescription" );
+		final Element ImageLoader = SequenceDescription.getChild( "ImageLoader" );
+
+		ImageLoader.setAttribute( "format", "bdv.remote" );
+
+		ImageLoader.removeChild( "hdf5" );
+
+		final Element baseUrl = new Element( "baseUrl" );
+		baseUrl.setText( dataSetURL );
+		ImageLoader.setContent( baseUrl );
+
+//		System.out.println(ImageLoader.getAttribute( "format" ));
+//		System.out.println(ImageLoader.getValue());
+
+		response.setContentType( "application/xml" );
+		response.setStatus( HttpServletResponse.SC_OK );
+		baseRequest.setHandled( true );
+		final PrintWriter ow = response.getWriter();
+		ow.write( new XMLOutputter().outputString( doc ) );
+		ow.close();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/bdv/server/DataSetHandler.java b/src/main/java/bdv/server/DataSetHandler.java
new file mode 100644
index 0000000..8e66076
--- /dev/null
+++ b/src/main/java/bdv/server/DataSetHandler.java
@@ -0,0 +1,46 @@
+package bdv.server;
+
+import mpicbg.spim.data.SpimDataException;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.handler.AbstractHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.HashMap;
+
+public class DataSetHandler extends AbstractHandler
+{
+	final private HashMap< String, CellHandler > cellHandlers;
+
+	public DataSetHandler( String baseURL, HashMap< String, String > ds ) throws SpimDataException, MalformedURLException
+	{
+		cellHandlers = new HashMap<>();
+
+		for ( String dataSet : ds.keySet() )
+		{
+			cellHandlers.put( dataSet, new CellHandler( baseURL + dataSet + "/", ds.get( dataSet ) ) );
+		}
+	}
+
+	@Override
+	public void handle( final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException
+	{
+		String dsName = target.replace( "/", "" );
+
+		if ( cellHandlers.containsKey( dsName ) )
+		{
+			if ( request.getParameter( "p" ) != null )
+				cellHandlers.get( dsName ).handle( target, baseRequest, request, response );
+			else
+				// Provide XML file
+				cellHandlers.get( dsName ).provideXML( baseRequest, response );
+		}
+		else
+		{
+			return;
+		}
+	}
+}
-- 
GitLab