From 624432ba381a63b2189f15269b630b1476321d7a Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Mon, 5 Oct 2015 16:58:00 +0200 Subject: [PATCH 01/15] When manager is enabled, force to have a dataset list file --- src/main/java/bdv/server/BigDataServer.java | 26 ++++++--------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index 79cf3d0..bab2cda 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -326,11 +326,13 @@ static private Parameters processOptions( final String[] args, final Parameters final String securePortString = cmd.getOptionValue( "mp", Integer.toString( defaultParameters.getSslport() ) ); sslPort = Integer.parseInt( securePortString ); + + if ( !cmd.hasOption( "d" ) ) + throw new IllegalArgumentException( "Dataset list file is necessary for BigDataServer manager" ); } } // Path for holding the dataset file - Path readDatasetFilePath; if ( cmd.hasOption( "d" ) ) { // process the file given with "-d" @@ -342,25 +344,8 @@ static private Parameters processOptions( final String[] args, final Parameters if ( Files.notExists( path ) ) throw new IllegalArgumentException( "Dataset list file does not exist." ); - readDatasetFilePath = path; + readDatasetFile( datasets, path ); } - else - { - // If the user does not provide any dataset file, - // we keep the adding dataset in {Working folder}/.data/list.txt - final Path datasetFileFolderPath = Paths.get( System.getProperty( "user.dir" ) + "/.data" ); - - if ( Files.notExists( datasetFileFolderPath ) ) - Files.createDirectory( datasetFileFolderPath ); - - final Path datasetFilePath = Paths.get( System.getProperty( "user.dir" ) + "/.data/list.txt" ); - - if ( Files.notExists( datasetFilePath ) ) - Files.createFile( datasetFilePath ); - - readDatasetFilePath = datasetFilePath; - } - readDatasetFile( datasets, readDatasetFilePath ); // process additional {name, name.xml} pairs given on the // command-line @@ -375,6 +360,9 @@ static private Parameters processOptions( final String[] args, final Parameters tryAddDataset( datasets, name, xmlpath ); } + if ( datasets.isEmpty() ) + throw new IllegalArgumentException( "Dataset list is empty." ); + return new Parameters( port, sslPort, serverName, datasets, thumbnailDirectory, enableManagerContext ); } catch ( final ParseException | IllegalArgumentException e ) From 6f47decf107ac2bf3f3c345729c1c62bf5f41420 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Mon, 5 Oct 2015 17:01:54 +0200 Subject: [PATCH 02/15] Remove EXPERIMENTAL constant --- src/main/java/bdv/server/BigDataServer.java | 42 +++++++++------------ src/main/java/bdv/server/Constants.java | 2 - 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index bab2cda..2c2296c 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -43,11 +43,10 @@ * -s <HOSTNAME> Hostname of the server. * -t <DIRECTORY> Directory to store thumbnails. (new temporary directory * by default.) - * -m enable statistics and manager context. EXPERIMENTAL! + * -m Enable statistics and manager context. + * -mp Manager context HTTPS port. * * - * To enable the {@code -m} option, build with - * {@link Constants#ENABLE_EXPERIMENTAL_FEATURES} set to {@code true}. * * @author Tobias Pietzsch * @author HongKee Moon @@ -286,18 +285,15 @@ static private Parameters processOptions( final String[] args, final Parameters .withArgName( "DIRECTORY" ) .create( "t" ) ); - if ( Constants.ENABLE_EXPERIMENTAL_FEATURES ) - { - options.addOption( OptionBuilder - .withDescription( "Enable statistics and manager context. EXPERIMENTAL!" ) - .create( "m" ) ); - - options.addOption( OptionBuilder - .withDescription( "Manager context HTTPS port. EXPERIMENTAL!" + "\n(default: " + defaultParameters.getSslport() + ")" ) - .hasArg() - .withArgName( "SECURE_PORT" ) - .create( "mp" ) ); - } + options.addOption( OptionBuilder + .withDescription( "Enable statistics and manager context." ) + .create( "m" ) ); + + options.addOption( OptionBuilder + .withDescription( "Manager context HTTPS port." + "\n(default: " + defaultParameters.getSslport() + ")" ) + .hasArg() + .withArgName( "SECURE_PORT" ) + .create( "mp" ) ); try { @@ -318,18 +314,16 @@ static private Parameters processOptions( final String[] args, final Parameters boolean enableManagerContext = false; int sslPort = defaultParameters.getSslport(); - if ( Constants.ENABLE_EXPERIMENTAL_FEATURES ) + + if ( cmd.hasOption( "m" ) ) { - if ( cmd.hasOption( "m" ) ) - { - enableManagerContext = true; + enableManagerContext = true; - final String securePortString = cmd.getOptionValue( "mp", Integer.toString( defaultParameters.getSslport() ) ); - sslPort = Integer.parseInt( securePortString ); + final String securePortString = cmd.getOptionValue( "mp", Integer.toString( defaultParameters.getSslport() ) ); + sslPort = Integer.parseInt( securePortString ); - if ( !cmd.hasOption( "d" ) ) - throw new IllegalArgumentException( "Dataset list file is necessary for BigDataServer manager" ); - } + if ( !cmd.hasOption( "d" ) ) + throw new IllegalArgumentException( "Dataset list file is necessary for BigDataServer manager" ); } // Path for holding the dataset file diff --git a/src/main/java/bdv/server/Constants.java b/src/main/java/bdv/server/Constants.java index f11adae..45d56dc 100644 --- a/src/main/java/bdv/server/Constants.java +++ b/src/main/java/bdv/server/Constants.java @@ -15,6 +15,4 @@ public class Constants public static final int THUMBNAIL_WIDTH = 100; public static final int THUMBNAIL_HEIGHT = 100; - - public static final boolean ENABLE_EXPERIMENTAL_FEATURES = false; } From f065e10c61dca86d1e691ba13579bd3827e5a20a Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Mon, 5 Oct 2015 17:09:59 +0200 Subject: [PATCH 03/15] Add final to the local variables --- src/main/java/bdv/server/BigDataServer.java | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index 2c2296c..0ce6e56 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -92,7 +92,7 @@ public static void main( final String[] args ) throws Exception httpConfig.setSecurePort( params.getSslport() ); // Setup buffers on http - HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory( httpConfig ); + final HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory( httpConfig ); httpConnectionFactory.setInputBufferSize( 64 * 1024 ); // ServerConnector configuration @@ -113,17 +113,17 @@ public static void main( final String[] args ) throws Exception Handler handler = handlers; if ( params.enableManagerContext() ) { - HttpConfiguration https = new HttpConfiguration(); + final HttpConfiguration https = new HttpConfiguration(); https.addCustomizer( new SecureRequestCustomizer() ); // Please, change localhost according to your site name // keytool -genkey -alias localhost -keyalg RSA -keystore keystore.jks -keysize 2048 - SslContextFactory sslContextFactory = new SslContextFactory(); + final SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath( Resource.newClassPathResource( "etc/keystore.jks" ).toString() ); sslContextFactory.setKeyStorePassword( "123456" ); sslContextFactory.setKeyManagerPassword( "123456" ); - ServerConnector sslConnector = new ServerConnector( server, + final ServerConnector sslConnector = new ServerConnector( server, new SslConnectionFactory( sslContextFactory, "http/1.1" ), new HttpConnectionFactory( https ) ); sslConnector.setHost( params.getHostname() ); @@ -140,30 +140,30 @@ public static void main( final String[] args ) throws Exception handlers.addHandler( new ManagerHandler( baseURL, server, connectorStats, statHandler, datasetHandlers, thumbnailsDirectoryName ) ); statHandler.setHandler( handlers ); - Constraint constraint = new Constraint(); + final Constraint constraint = new Constraint(); constraint.setName( Constraint.__BASIC_AUTH ); constraint.setRoles( new String[] { "admin", "superuser" } ); constraint.setAuthenticate( true ); // 2 means CONFIDENTIAL. 1 means INTEGRITY constraint.setDataConstraint( Constraint.DC_CONFIDENTIAL ); - ConstraintMapping cm = new ConstraintMapping(); - cm.setPathSpec( "/manager/*" ); + final ConstraintMapping cm = new ConstraintMapping(); + cm.setPathSpec( "/ " + Constants.MANAGER_CONTEXT_NAME + "/*" ); cm.setConstraint( constraint ); // Please change the password in realm.properties - HashLoginService loginService = new HashLoginService( "BigDataServerRealm", Resource.newClassPathResource( "etc/realm.properties" ).toString() ); + final HashLoginService loginService = new HashLoginService( "BigDataServerRealm", Resource.newClassPathResource( "etc/realm.properties" ).toString() ); server.addBean( loginService ); - HandlerList handlerList = new HandlerList(); + final HandlerList handlerList = new HandlerList(); - ContextHandler redirectHandler = new ContextHandler(); + final ContextHandler redirectHandler = new ContextHandler(); redirectHandler.setContextPath( "/" + Constants.MANAGER_CONTEXT_NAME ); redirectHandler.setHandler( new SecuredRedirectHandler() ); handlerList.addHandler( redirectHandler ); - ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); + final ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); sh.setLoginService( loginService ); sh.setAuthenticator( new BasicAuthenticator() ); sh.addConstraintMapping( cm ); From 400264d5c8c846e6323a2ee4ce4c012b2b9e55fc Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Mon, 5 Oct 2015 17:11:14 +0200 Subject: [PATCH 04/15] Remove the redirect handler --- src/main/java/bdv/server/BigDataServer.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index 0ce6e56..a78407c 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -155,20 +155,13 @@ public static void main( final String[] args ) throws Exception final HashLoginService loginService = new HashLoginService( "BigDataServerRealm", Resource.newClassPathResource( "etc/realm.properties" ).toString() ); server.addBean( loginService ); - final HandlerList handlerList = new HandlerList(); - - final ContextHandler redirectHandler = new ContextHandler(); - redirectHandler.setContextPath( "/" + Constants.MANAGER_CONTEXT_NAME ); - redirectHandler.setHandler( new SecuredRedirectHandler() ); - - handlerList.addHandler( redirectHandler ); - final ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); sh.setLoginService( loginService ); sh.setAuthenticator( new BasicAuthenticator() ); sh.addConstraintMapping( cm ); sh.setHandler( statHandler ); + final HandlerList handlerList = new HandlerList(); handlerList.addHandler( sh ); handler = handlerList; From 981dc0dc6cafb41c52012cfcf4f522ad2cd5b728 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Mon, 5 Oct 2015 17:12:05 +0200 Subject: [PATCH 05/15] Remove superuser role --- src/main/java/bdv/server/BigDataServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index a78407c..50acdb7 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -142,7 +142,7 @@ public static void main( final String[] args ) throws Exception final Constraint constraint = new Constraint(); constraint.setName( Constraint.__BASIC_AUTH ); - constraint.setRoles( new String[] { "admin", "superuser" } ); + constraint.setRoles( new String[] { "admin" } ); constraint.setAuthenticate( true ); // 2 means CONFIDENTIAL. 1 means INTEGRITY constraint.setDataConstraint( Constraint.DC_CONFIDENTIAL ); From 6cceb43217bc8cd1f2eb15fdcaf7a9831a1f313c Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Tue, 6 Oct 2015 13:55:52 +0200 Subject: [PATCH 06/15] Remove the all the credential information All the important information are required to have in the initial run with /manager context enabled. SSL certificate and jetty user property files are located under current_working_folder/etc. Whenever users want to update the critical information, they can modify them directly. --- src/main/java/bdv/server/BigDataServer.java | 269 +++++++++++++++++++- src/main/resources/etc/keystore.jks | Bin 2247 -> 0 bytes src/main/resources/etc/realm.properties | 11 - 3 files changed, 261 insertions(+), 19 deletions(-) delete mode 100644 src/main/resources/etc/keystore.jks delete mode 100644 src/main/resources/etc/realm.properties diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index 50acdb7..a36b108 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -13,20 +13,61 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Password; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.thread.QueuedThreadPool; - +import sun.security.x509.AlgorithmId; +import sun.security.x509.CertificateAlgorithmId; +import sun.security.x509.CertificateIssuerName; +import sun.security.x509.CertificateSerialNumber; +import sun.security.x509.CertificateSubjectName; +import sun.security.x509.CertificateValidity; +import sun.security.x509.CertificateVersion; +import sun.security.x509.CertificateX509Key; +import sun.security.x509.X500Name; +import sun.security.x509.X509CertImpl; +import sun.security.x509.X509CertInfo; + +import java.io.BufferedInputStream; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.util.Date; +import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Serve XML/HDF5 datasets over HTTP. @@ -113,15 +154,22 @@ public static void main( final String[] args ) throws Exception Handler handler = handlers; if ( params.enableManagerContext() ) { + if ( !checkKeystore() ) + throw new IllegalArgumentException( "Keystore file does not exist." ); + + if ( !checkRealmProperty() ) + throw new IllegalArgumentException( "Login property file does not exist." ); + final HttpConfiguration https = new HttpConfiguration(); https.addCustomizer( new SecureRequestCustomizer() ); - // Please, change localhost according to your site name - // keytool -genkey -alias localhost -keyalg RSA -keystore keystore.jks -keysize 2048 final SslContextFactory sslContextFactory = new SslContextFactory(); - sslContextFactory.setKeyStorePath( Resource.newClassPathResource( "etc/keystore.jks" ).toString() ); - sslContextFactory.setKeyStorePassword( "123456" ); - sslContextFactory.setKeyManagerPassword( "123456" ); + sslContextFactory.setKeyStorePath( "etc/keystore.jks" ); + + final char passwordArray[] = System.console().readPassword( "Please, enter your keystore password: " ); + String password = new String( passwordArray ); + sslContextFactory.setKeyStorePassword( password ); + sslContextFactory.setKeyManagerPassword( password ); final ServerConnector sslConnector = new ServerConnector( server, new SslConnectionFactory( sslContextFactory, "http/1.1" ), @@ -148,11 +196,11 @@ public static void main( final String[] args ) throws Exception constraint.setDataConstraint( Constraint.DC_CONFIDENTIAL ); final ConstraintMapping cm = new ConstraintMapping(); - cm.setPathSpec( "/ " + Constants.MANAGER_CONTEXT_NAME + "/*" ); + cm.setPathSpec( "/" + Constants.MANAGER_CONTEXT_NAME + "/*" ); cm.setConstraint( constraint ); // Please change the password in realm.properties - final HashLoginService loginService = new HashLoginService( "BigDataServerRealm", Resource.newClassPathResource( "etc/realm.properties" ).toString() ); + final HashLoginService loginService = new HashLoginService( "BigDataServerRealm", "etc/realm.properties" ); server.addBean( loginService ); final ConstraintSecurityHandler sh = new ConstraintSecurityHandler(); @@ -175,6 +223,211 @@ public static void main( final String[] args ) throws Exception server.join(); } + private static boolean checkKeystore() + { + // check if "etc/keystore.jks" exists + if ( Files.exists( Paths.get( "etc/keystore.jks" ) ) ) + return true; + else + { + try + { + // keytool -genkey -alias localhost -keyalg RSA -keystore keystore.jks -keysize 2048 + if ( Files.notExists( Paths.get( "etc/" ) ) ) + Files.createDirectory( Paths.get( "etc/" ) ); + + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "RSA" ); + keyPairGenerator.initialize( 2048 ); + KeyPair KPair = keyPairGenerator.generateKeyPair(); + PrivateKey privkey = KPair.getPrivate(); + + X509CertInfo info = new X509CertInfo(); + Date from = new Date(); + Date to = new Date( from.getTime() + 365 * 86400000l ); + CertificateValidity interval = new CertificateValidity( from, to ); + BigInteger sn = new BigInteger( 64, new SecureRandom() ); + X500Name owner = new X500Name( "CN=Unknown, L=Unknown, ST=Unknown, O=Unknown, OU=Unknown, C=Unknown" ); + + info.set( X509CertInfo.VALIDITY, interval ); + info.set( X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber( sn ) ); + boolean justName = isJavaAtLeast( 1.8 ); + if ( justName ) + { + info.set( X509CertInfo.SUBJECT, owner ); + info.set( X509CertInfo.ISSUER, owner ); + } + else + { + info.set( X509CertInfo.SUBJECT, new CertificateSubjectName( owner ) ); + info.set( X509CertInfo.ISSUER, new CertificateIssuerName( owner ) ); + } + + info.set( X509CertInfo.KEY, new CertificateX509Key( KPair.getPublic() ) ); + info.set( X509CertInfo.VERSION, new CertificateVersion( CertificateVersion.V3 ) ); + AlgorithmId algo = new AlgorithmId( AlgorithmId.sha256WithRSAEncryption_oid ); + info.set( X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId( algo ) ); + + // Sign the cert to identify the algorithm that's used. + X509CertImpl cert = new X509CertImpl( info ); + cert.sign( privkey, "SHA256withRSA" ); + + // Update the algorithm, and resign. + algo = ( AlgorithmId ) cert.get( X509CertImpl.SIG_ALG ); + info.set( CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo ); + cert = new X509CertImpl( info ); + cert.sign( privkey, "SHA256withRSA" ); + + KeyStore keyStore = null; + FileOutputStream keyStoreFile = null; + + // Load the default Java keystore + keyStore = KeyStore.getInstance( KeyStore.getDefaultType() ); + keyStore.load( null, "changeit".toCharArray() ); + + final char passwordArray[] = System.console().readPassword( "Enter your new keystore password for SSL connection: " ); + + String password = new String( passwordArray ); + + // Put our information + keyStore.setCertificateEntry( "localhost", cert ); + keyStore.setKeyEntry( "localhost", privkey, + password.toCharArray(), + new java.security.cert.Certificate[] { cert } ); + + // Generate new cert + keyStoreFile = new FileOutputStream( "etc/keystore.jks" ); + keyStore.store( keyStoreFile, password.toCharArray() ); + keyStoreFile.close(); + } + catch ( FileNotFoundException e ) + { + e.printStackTrace(); + return false; + } + catch ( KeyStoreException e ) + { + e.printStackTrace(); + return false; + } + catch ( IOException e ) + { + e.printStackTrace(); + return false; + } + catch ( NoSuchAlgorithmException e ) + { + e.printStackTrace(); + return false; + } + catch ( CertificateException e ) + { + e.printStackTrace(); + return false; + } + catch ( SignatureException e ) + { + e.printStackTrace(); + return false; + } + catch ( NoSuchProviderException e ) + { + e.printStackTrace(); + return false; + } + catch ( InvalidKeyException e ) + { + e.printStackTrace(); + return false; + } + } + return true; + } + + public static final Pattern JAVA_VERSION = Pattern.compile( "([0-9]*.[0-9]*)(.*)?" ); + + /** + * Checks whether the current Java runtime has a version equal or higher then the given one. As Java version are + * not double (because they can use more digits such as 1.8.0), this method extracts the two first digits and + * transforms it as a double. + * @param version the version + * @return {@literal true} if the current Java runtime is at least the specified one, + * {@literal false} if not or if the current version cannot be retrieve or is the retrieved version cannot be + * parsed as a double. + */ + public static boolean isJavaAtLeast( double version ) + { + String javaVersion = System.getProperty( "java.version" ); + if ( javaVersion == null ) + { + return false; + } + + // if the retrieved version is one three digits, remove the last one. + Matcher matcher = JAVA_VERSION.matcher( javaVersion ); + if ( matcher.matches() ) + { + javaVersion = matcher.group( 1 ); + } + + try + { + double v = Double.parseDouble( javaVersion ); + return v >= version; + } + catch ( NumberFormatException e ) + { + return false; + } + } + + private static boolean checkRealmProperty() + { + Path path = Paths.get( "etc/realm.properties" ); + // check if "etc/realm.properties" exists + if ( Files.exists( path ) ) + return true; + else + { + try + { + if ( Files.notExists( Paths.get( "etc/" ) ) ) + Files.createDirectory( Paths.get( "etc/" ) ); + + final String userId = System.console().readLine( "Enter your ID for manager : " ); + final char passwordArray[] = System.console().readPassword( "Enter your password for \"%s\": ", userId ); + + String md5 = Password.MD5.digest( new String( passwordArray ) ); + + BufferedWriter writer = Files.newBufferedWriter( path, StandardCharsets.UTF_8 ); + + writer.append( "# http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html\n" ); + writer.append( "# Please, use obfuscated/MD5/crypted password only by using below instructions\n" ); + writer.append( "#\n" ); + writer.append( "# \t$ export JETTY_VERSION=9.0.0.RC0\n" ); + writer.append( "# \t$ java -cp lib/jetty-util-$JETTY_VERSION.jar org.eclipse.jetty.util.security.Password username blahblah\n" ); + writer.append( "# \tOBF:20771x1b206z\n" ); + writer.append( "# \tMD5:639bae9ac6b3e1a84cebb7b403297b79\n" ); + writer.append( "# \tCRYPT:me/ks90E221EY\n" ); + + writer.newLine(); + writer.append( userId ); + writer.append( ": " ); + writer.append( md5 ); + writer.append( ", admin" ); + writer.newLine(); + + writer.flush(); + writer.close(); + } + catch ( IOException e ) + { + e.printStackTrace(); + return false; + } + } + return true; + } + /** * Server parameters: hostname, port, sslPort, datasets. */ diff --git a/src/main/resources/etc/keystore.jks b/src/main/resources/etc/keystore.jks deleted file mode 100644 index 9b493f5501caa772c5338015e4556dfa6bd97acd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2247 zcmchYX*84#AI9%{W|AdjVi;LNS}gZuCnPB&WFN$kEMuFo%uC3=GYNwvG9)~Yp=8gV z$C^+?O7<<1rih1(*Xg|Pd!BRp{(iVVT)$8MbDis4f94u<4FCYxfxus4^CI26;YA?% zlMjetko?gz0B{HfMIo3F7YqAY77ziRf$@OgApjADSZN@x1zxL44QCdAE*--&uUrhB z5b)K;WVs+3t;N`y><#sKQS+Z;ZB0WL8sf*RlIANqvFsCaD8;_^Ec;{|+1eg`^Cs)=J-}n8+vUo@Jl2f#3 zAG#uVB-LlJX*|nzf!j6HH|cY>h{39&v4{A63pvZ$N550&6*~AW>xtV-a82}W2ez4WR zPwR?B)2AMbB}`qJ3vpTEb=~PRuSGqc3{wao(qQ6>eB`HdYIHv3^JxWJ4?4*`U8@bd z!Mh@H($WH{e|(1JTwuVhZd;dTF4Ol5AViz?7#(x^u@B z6$y_0R0+B_L3D%|o4=tUi9RY{a*{Hc|7d~7l?ZUCz8(M3mdoZAyc^AJegbB?#mAoE zkuEs9ygH26Rp|Bf{m~Y!e4M4W&q?9=*gD_nEo)+|mHm8riZ#cjEr08m2@@txj4$lc z-MmFUxRYfeOyo61$F9Qgh!ERQ!Ygd=h1tn+nuT;5*^yjX2Onm_dZ{U15jSP_e@0Q+ zC&BCGMrEwncTI{J1pOmYW~z(n4DZ#b?q*cNxaQMjH14&Pm`g^EcowjufE{h!7OKf~ z8C202Xkao0_Y3A|93@N8h8q`RjQBp&+wcCp#iq~;Ep=_>0nX;_Y1r7!?vybFUfscqfCY@!tcj1E@k_ACn&yOX>z!$9&2K2Fk-wg(-ucjotnNgTe_D z@(?cmgeAnKLrR|!eE=x&u z&f~j}`!>@3^70ft-a+|IoN-Da0H}hO*Q=Fhv@o2f+Kuv(lSHfgdW9m=boB;Jj)=q5 z9VzwM%OOKFS%F~ZF-K$Heu`N2z1A<>G14ED!_flL8lOj=7)cDZ2HjcC5=mM@-)!vP zI;&+or#oG>cxuxB*_?XFOFYIiWcfvTn_u3LFNbhR*3C0!nS?B<;&(+hx0K@i?mBjc zj^X`5#H`YuaN_L9B@CM`mzisgpH^>JVdc;YyBwkZEp&3wZsKx>nWJ%{N()EWmcuLB zY?VLKD2AGgH`f*gkc$P07yU^3yB2$o}qEs35)QXuia zg!MOa_&37-8{znk!2d@e5q?gL5~K*7gH$mX2xI%psz8|k*#Gl2QQ(Px#&Pg1;87qq z07Zf9uqY4&hA(8)weKwNCE4l7u8kUN8`-FnO7qKd6=nx){*<>@PE9M6)~^|lSW7Hn z(KhKaAj`3_5pA8-D1t;1tJs~Z`FVO=O2Ks+YN8Gm9rg?t^Nk|I0+V$l|Kk`|;g1dW zrM4HFy@Cbbq-Jh6W*&K_q^~qxog^jBmm}0D*4lFF3ZnsO5_7|iFY&HrKKgbvOo}fN z)~RvYi7Nf5_ow;Z{i5;)JC~CF=#!CXO6TJnp#r&F?i+n#YQC zCB^xxWw`XLf$o{I4$PjA_CRP*WF6VLdghCg+$z;8Ui}!7uJ!Xlwf9rL@B!9(+54Mi z$(%iR!eMX_03V4%qLA=GLxi~yCY)As%$;R8J$6ZCXPXaO#8Ht4vD-N$E? zb7_CKn=!^HKY~$IIqZ(?n^t6qsp#qHXLCw#s>?4Ah}*2Wqqy6L^q!J#^n1n6K2u9i zl$4)KDKT>GG7Q~BhtYKLPfx8s)!bM4K089FWWjcG`YhpN$-z>-n?bH>%$AWHeb)tz zzAPze4*%OLSHC9ZD35Lk1t@xr=8minecLbiilxfFzg Date: Mon, 12 Oct 2015 16:09:57 +0200 Subject: [PATCH 07/15] Remove unnecessary imports --- src/main/java/bdv/server/BigDataServer.java | 35 ++++++--------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index a36b108..c4e39dc 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -11,7 +11,6 @@ import org.eclipse.jetty.server.*; import org.eclipse.jetty.server.handler.*; import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.security.Password; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -28,16 +27,10 @@ import sun.security.x509.X509CertImpl; import sun.security.x509.X509CertInfo; -import java.io.BufferedInputStream; import java.io.BufferedWriter; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; @@ -55,17 +48,12 @@ import java.security.PrivateKey; import java.security.SecureRandom; import java.security.SignatureException; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; import java.util.Date; -import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -87,8 +75,6 @@ * -m Enable statistics and manager context. * -mp Manager context HTTPS port. * - * - * * @author Tobias Pietzsch * @author HongKee Moon */ @@ -480,7 +466,6 @@ public String getThumbnailDirectory() /** * Get datasets. - * * @return datasets as a map from dataset name to dataset xml path. */ public Map< String, DataSet > getDatasets() @@ -649,12 +634,12 @@ else if ( tokens.length == 5 ) } } - private static void tryAddDataset( final HashMap< String, DataSet > datasetNameToDataSet, final String ... args ) throws IllegalArgumentException + private static void tryAddDataset( final HashMap< String, DataSet > datasetNameToDataSet, final String... args ) throws IllegalArgumentException { - if ( args.length >= 2) + if ( args.length >= 2 ) { - final String name = args[0]; - final String xmlpath = args[1]; + final String name = args[ 0 ]; + final String xmlpath = args[ 1 ]; for ( final String reserved : Constants.RESERVED_CONTEXT_NAMES ) if ( name.equals( reserved ) ) @@ -668,11 +653,11 @@ private static void tryAddDataset( final HashMap< String, DataSet > datasetNameT String desc = ""; String index = ""; - if( args.length == 5 ) + if ( args.length == 5 ) { - category = args[2]; - desc = args[3]; - index = args[4]; + category = args[ 2 ]; + desc = args[ 3 ]; + index = args[ 4 ]; } DataSet ds = new DataSet( name, xmlpath, category, desc, index ); @@ -687,7 +672,7 @@ private static String getThumbnailDirectoryPath( final Parameters params ) throw if ( thumbnailDirectoryName != null ) { Path thumbnails = Paths.get( thumbnailDirectoryName ); - if ( ! Files.exists( thumbnails ) ) + if ( !Files.exists( thumbnails ) ) { try { @@ -702,7 +687,7 @@ private static String getThumbnailDirectoryPath( final Parameters params ) throw } else { - if ( ! Files.isDirectory( thumbnails ) ) + if ( !Files.isDirectory( thumbnails ) ) LOG.warn( "Thumbnails directory \"" + thumbnailDirectoryName + "\" is not a directory.\n Trying to create temporary directory." ); else return thumbnails.toFile().getAbsolutePath(); From b236c8c78029082fce4041b2c4bd2f5206b787da Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Mon, 12 Oct 2015 16:32:31 +0200 Subject: [PATCH 08/15] Keep 5 back-up files when the data list file is saved --- src/main/java/bdv/model/DataSet.java | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/java/bdv/model/DataSet.java b/src/main/java/bdv/model/DataSet.java index 48fe116..f39bb1c 100644 --- a/src/main/java/bdv/model/DataSet.java +++ b/src/main/java/bdv/model/DataSet.java @@ -1,10 +1,14 @@ package bdv.model; +import org.eclipse.jetty.util.log.Log; + import java.io.BufferedWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; /** @@ -12,6 +16,8 @@ */ public class DataSet { + private static final org.eclipse.jetty.util.log.Logger LOG = Log.getLogger( DataSet.class ); + private static Path dataSetListPath; /** * DataSet Context name of this {@link bdv.server.CellHandler} is serving. @@ -31,6 +37,8 @@ public class DataSet private String thumbnailUrl; private String datasetUrl; + public static int numBackups = 5; + /** * Instantiates a new DataSet * @@ -198,6 +206,34 @@ public static void storeDataSet( ArrayList< DataSet > list ) throws IOException { if ( dataSetListPath != null ) { + // fist make a copy of the XML and save it to not loose it + if ( Files.exists( dataSetListPath ) ) + { + int maxExistingBackup = 0; + for ( int i = 1; i < numBackups; ++i ) + if ( Files.exists( Paths.get( dataSetListPath + "~" + i ) ) ) + maxExistingBackup = i; + else + break; + + // copy the backups + try + { + for ( int i = maxExistingBackup; i >= 1; --i ) + Files.copy( Paths.get( dataSetListPath + "~" + i ), + Paths.get( dataSetListPath + "~" + ( i + 1 ) ), + StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING ); + + Files.copy( dataSetListPath, Paths.get( dataSetListPath + "~" + 1 ), + StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING ); + } + catch ( final IOException e ) + { + LOG.warn( "Could not save backup of data list file: " + e ); + e.printStackTrace(); + } + } + BufferedWriter writer = Files.newBufferedWriter( dataSetListPath, StandardCharsets.UTF_8 ); for ( DataSet ds : list ) { From f3f955133014cc0b279ae5d9edbec9312f597a37 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Wed, 11 Nov 2015 12:21:20 +0100 Subject: [PATCH 09/15] Fix the activation bug It should have given the dataset name instead of the category name. --- src/main/resources/webapp/pages/datasets.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/webapp/pages/datasets.html b/src/main/resources/webapp/pages/datasets.html index 7051e36..ea25544 100644 --- a/src/main/resources/webapp/pages/datasets.html +++ b/src/main/resources/webapp/pages/datasets.html @@ -241,7 +241,7 @@

Dataset deployment

$.ajax({ type: "POST", url: "/manager/?op=activate", - data: { name: $(this).parent().next().text(), active: $(this).prop('checked')}, + data: { name: $(this).parent().next().next().next().text(), active: $(this).prop('checked')}, success: function (msg) { console.info("Dataset activated: " + msg); } From 3fdcd640cc82b4271b37f559902a3d266e2501ef Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Thu, 3 Dec 2015 16:19:59 +0100 Subject: [PATCH 10/15] Replace -mp option by -m If -m option present, it enables manager context. --- src/main/java/bdv/server/BigDataServer.java | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index c4e39dc..7a1d45d 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -68,12 +68,13 @@ * is the path to the XML file of the dataset. * -d <FILE> Dataset file: A plain text file specifying one dataset * per line. Each line is formatted as "NAME <TAB> XML". - * -p <PORT> Listening port. (default: 8080) + * -m <SECURE_PORT>Manager context HTTPS port. The manager context is automatically enabled. + * (default: 8443) + * -p <PORT> Listening port. + * (default: 8080) * -s <HOSTNAME> Hostname of the server. * -t <DIRECTORY> Directory to store thumbnails. (new temporary directory * by default.) - * -m Enable statistics and manager context. - * -mp Manager context HTTPS port. * * @author Tobias Pietzsch * @author HongKee Moon @@ -517,14 +518,10 @@ static private Parameters processOptions( final String[] args, final Parameters .create( "t" ) ); options.addOption( OptionBuilder - .withDescription( "Enable statistics and manager context." ) - .create( "m" ) ); - - options.addOption( OptionBuilder - .withDescription( "Manager context HTTPS port." + "\n(default: " + defaultParameters.getSslport() + ")" ) + .withDescription( "Manager context HTTPS port. The manager context is automatically enabled." + "\n(default: " + defaultParameters.getSslport() + ")" ) .hasArg() .withArgName( "SECURE_PORT" ) - .create( "mp" ) ); + .create( "m" ) ); try { @@ -550,7 +547,7 @@ static private Parameters processOptions( final String[] args, final Parameters { enableManagerContext = true; - final String securePortString = cmd.getOptionValue( "mp", Integer.toString( defaultParameters.getSslport() ) ); + final String securePortString = cmd.getOptionValue( "m", Integer.toString( defaultParameters.getSslport() ) ); sslPort = Integer.parseInt( securePortString ); if ( !cmd.hasOption( "d" ) ) From 418ae05a4de02a09477616d3089ae76b75996c9c Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Thu, 3 Dec 2015 17:36:08 +0100 Subject: [PATCH 11/15] Add IndexPageHandler for supporting web browser --- src/main/java/bdv/server/BigDataServer.java | 1 + .../java/bdv/server/IndexPageHandler.java | 128 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 src/main/java/bdv/server/IndexPageHandler.java diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index 7a1d45d..7458ab4 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -137,6 +137,7 @@ public static void main( final String[] args ) throws Exception final ContextHandlerCollection datasetHandlers = createHandlers( baseURL, params.getDatasets(), thumbnailsDirectoryName ); handlers.addHandler( datasetHandlers ); handlers.addHandler( new JsonDatasetListHandler( server, datasetHandlers ) ); + handlers.addHandler( new IndexPageHandler( server, datasetHandlers ) ); Handler handler = handlers; if ( params.enableManagerContext() ) diff --git a/src/main/java/bdv/server/IndexPageHandler.java b/src/main/java/bdv/server/IndexPageHandler.java new file mode 100644 index 0000000..6ba698b --- /dev/null +++ b/src/main/java/bdv/server/IndexPageHandler.java @@ -0,0 +1,128 @@ +package bdv.server; + +import bdv.model.DataSet; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.io.PrintWriter; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +/** + * Provides the default index page of available datasets on this {@link BigDataServer} + * @author HongKee Moon + */ +public class IndexPageHandler extends ContextHandler +{ + private final Server server; + + public IndexPageHandler( final Server server, final ContextHandlerCollection handlers ) throws IOException, URISyntaxException + { + this.server = server; + setContextPath( "/" ); + } + + @Override + public void doHandle( final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException + { + list( baseRequest, response ); + } + + private void list( final Request baseRequest, final HttpServletResponse response ) throws IOException + { + response.setContentType( "text/html" ); + response.setStatus( HttpServletResponse.SC_OK ); + baseRequest.setHandled( true ); + + final PrintWriter ow = response.getWriter(); + getHtmlDatasetList( ow ); + ow.close(); + } + + private void getHtmlDatasetList( final PrintWriter out ) throws IOException + { + final ArrayList< DataSet > list = new ArrayList<>(); + + for ( final Handler handler : server.getChildHandlersByClass( CellHandler.class ) ) + { + CellHandler contextHandler = null; + if ( handler instanceof CellHandler ) + { + contextHandler = ( CellHandler ) handler; + + if ( contextHandler.isActive() ) + { + list.add( contextHandler.getDataSet() ); + } + } + } + + // Sort the list by Category and Index + Collections.sort( list, new Comparator< DataSet >() + { + @Override + public int compare( final DataSet lhs, DataSet rhs ) + { + // return 1 if rhs should be before lhs + // return -1 if lhs should be before rhs + // return 0 otherwise + if ( lhs.getCategory().equals( rhs.getCategory() ) ) + { + return lhs.getIndex().compareToIgnoreCase( rhs.getIndex() ); + } + else + { + return lhs.getCategory().compareToIgnoreCase( rhs.getCategory() ); + } + } + } ); + + // Build html table for dataset list + final StringBuilder sb = new StringBuilder(); + sb.append( "\n" ); + sb.append( "\n" ); + sb.append( "\n" ); + sb.append( "\n" ); + + sb.append( "
\n" ); + sb.append( "

BigDataServer DataSet list

" ); + sb.append( "\n" ); + + sb.append( "\n" ); + sb.append( "\n" ); + sb.append( "\n" ); + sb.append( "\n" ); + sb.append( "\n" ); + sb.append( "\n" ); + + for ( DataSet ds : list ) + { + sb.append( "\n" ); + sb.append( "\t\n" ); + sb.append( "\t\n" ); + sb.append( "\n" ); + } + sb.append( "
DataSetDescription
\n" ); + sb.append( "\t\t\n" ); + sb.append( "\t\n" ); + sb.append( "\t\tCategory: " + ds.getCategory() + "
\n" ); + sb.append( "\t\tName: " + ds.getName() + "
\n" ); + sb.append( "\t\tDescription: " + ds.getDescription() + "
\n" ); + sb.append( "\t
\n" ); + sb.append( "
\n" ); + sb.append( "\n" ); + + out.write( sb.toString() ); + out.close(); + } +} \ No newline at end of file From 45162e5a03e39485d2e8b9401a26ffb90108c6a3 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Thu, 17 Mar 2016 11:10:00 +0100 Subject: [PATCH 12/15] Move addition of IndexPageHandler to the end of the handler addition In order to avoid the overridden other context handlers --- src/main/java/bdv/server/BigDataServer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index 7458ab4..dd872f8 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -137,7 +137,6 @@ public static void main( final String[] args ) throws Exception final ContextHandlerCollection datasetHandlers = createHandlers( baseURL, params.getDatasets(), thumbnailsDirectoryName ); handlers.addHandler( datasetHandlers ); handlers.addHandler( new JsonDatasetListHandler( server, datasetHandlers ) ); - handlers.addHandler( new IndexPageHandler( server, datasetHandlers ) ); Handler handler = handlers; if ( params.enableManagerContext() ) @@ -203,6 +202,8 @@ public static void main( final String[] args ) throws Exception handler = handlerList; } + handlers.addHandler( new IndexPageHandler( server, datasetHandlers ) ); + LOG.info( "Set handler: " + handler ); server.setHandler( handler ); LOG.info( "Server Base URL: " + baseURL ); From 4bc62982c1d937de191f10992014be228a44c857 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Thu, 17 Mar 2016 14:15:16 +0100 Subject: [PATCH 13/15] Add super.doHandle() call in IndexPageHandler for the other contexts --- src/main/java/bdv/server/BigDataServer.java | 2 +- src/main/java/bdv/server/IndexPageHandler.java | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index dd872f8..c76e5a6 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -202,7 +202,7 @@ public static void main( final String[] args ) throws Exception handler = handlerList; } - handlers.addHandler( new IndexPageHandler( server, datasetHandlers ) ); + handlers.addHandler( new IndexPageHandler( server ) ); LOG.info( "Set handler: " + handler ); server.setHandler( handler ); diff --git a/src/main/java/bdv/server/IndexPageHandler.java b/src/main/java/bdv/server/IndexPageHandler.java index 6ba698b..422e559 100644 --- a/src/main/java/bdv/server/IndexPageHandler.java +++ b/src/main/java/bdv/server/IndexPageHandler.java @@ -5,7 +5,7 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.server.handler.HandlerCollection; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -26,7 +26,7 @@ public class IndexPageHandler extends ContextHandler { private final Server server; - public IndexPageHandler( final Server server, final ContextHandlerCollection handlers ) throws IOException, URISyntaxException + public IndexPageHandler( final Server server ) throws IOException, URISyntaxException { this.server = server; setContextPath( "/" ); @@ -35,7 +35,10 @@ public IndexPageHandler( final Server server, final ContextHandlerCollection han @Override public void doHandle( final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException { - list( baseRequest, response ); + if ( target.equals( "/" ) ) + list( baseRequest, response ); + else + super.doHandle( target, baseRequest, request, response ); } private void list( final Request baseRequest, final HttpServletResponse response ) throws IOException From 1c33a3a5254c39d6d45c94d919c730641b7664a2 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Fri, 22 Apr 2016 17:35:43 +0200 Subject: [PATCH 14/15] Add .bdv / .xml file handlers --- pom.xml | 8 +- src/main/java/bdv/server/BigDataServer.java | 8 +- src/main/java/bdv/server/CellHandler.java | 64 ++++++++++++++- src/main/java/bdv/server/Constants.java | 2 + .../bdv/server/DataSetContextHandler.java | 78 +++++++++++++++++++ .../java/bdv/server/IndexPageHandler.java | 7 ++ 6 files changed, 163 insertions(+), 4 deletions(-) create mode 100644 src/main/java/bdv/server/DataSetContextHandler.java diff --git a/pom.xml b/pom.xml index 6bd7bd7..a46ee15 100644 --- a/pom.xml +++ b/pom.xml @@ -48,8 +48,12 @@ org.eclipse.jetty jetty-security - - org.antlr + + org.eclipse.jetty + jetty-servlet + + + org.antlr stringtemplate 3.2.1 diff --git a/src/main/java/bdv/server/BigDataServer.java b/src/main/java/bdv/server/BigDataServer.java index c76e5a6..786150b 100644 --- a/src/main/java/bdv/server/BigDataServer.java +++ b/src/main/java/bdv/server/BigDataServer.java @@ -135,7 +135,13 @@ public static void main( final String[] args ) throws Exception final HandlerCollection handlers = new HandlerCollection(); final ContextHandlerCollection datasetHandlers = createHandlers( baseURL, params.getDatasets(), thumbnailsDirectoryName ); + + final DataSetContextHandler dataSetContextHandler = new DataSetContextHandler( datasetHandlers ); + handlers.addHandler( datasetHandlers ); + + handlers.addHandler( dataSetContextHandler ); + handlers.addHandler( new JsonDatasetListHandler( server, datasetHandlers ) ); Handler handler = handlers; @@ -705,7 +711,7 @@ private static ContextHandlerCollection createHandlers( final String baseURL, fi { final String name = entry.getKey(); final DataSet ds = entry.getValue(); - final String context = "/" + name; + final String context = "/" + Constants.DATASET_CONTEXT_NAME + "/" + name; final CellHandler ctx = new CellHandler( baseURL + context + "/", ds, thumbnailsDirectoryName ); ctx.setContextPath( context ); handlers.addHandler( ctx ); diff --git a/src/main/java/bdv/server/CellHandler.java b/src/main/java/bdv/server/CellHandler.java index 922f503..e9024c6 100644 --- a/src/main/java/bdv/server/CellHandler.java +++ b/src/main/java/bdv/server/CellHandler.java @@ -18,10 +18,12 @@ import com.google.gson.GsonBuilder; +import com.google.gson.stream.JsonWriter; import mpicbg.spim.data.SpimDataException; import net.imglib2.img.basictypeaccess.volatiles.array.VolatileShortArray; import net.imglib2.realtransform.AffineTransform3D; +import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.log.Log; @@ -84,6 +86,8 @@ public class CellHandler extends ContextHandler private Hdf5ImageLoader imgLoader; + private String baseUrl; + /** * DataSet information holder */ @@ -92,7 +96,7 @@ public class CellHandler extends ContextHandler public CellHandler( final String baseUrl, final DataSet dataSet, final String thumbnailsDirectory ) throws SpimDataException, IOException { active = true; - + this.baseUrl = baseUrl; this.dataSet = dataSet; final XmlIoSpimDataMinimal io = new XmlIoSpimDataMinimal(); @@ -139,6 +143,12 @@ public void doHandle( final String target, final Request baseRequest, final Http return; } + if ( target.startsWith( "/json" ) ) + { + provideJson( baseRequest, response ); + return; + } + if ( target.equals( "/png" ) ) { provideThumbnail( baseRequest, response ); @@ -374,4 +384,56 @@ public DataSet getDataSet() { return dataSet; } + + private void provideJson( final Request baseRequest, final HttpServletResponse response ) throws IOException + { + response.setContentType( "application/json" ); + response.setStatus( HttpServletResponse.SC_OK ); + baseRequest.setHandled( true ); + + final PrintWriter ow = response.getWriter(); + + final JsonWriter writer = new JsonWriter( ow ); + + writer.setIndent( "\t" ); + + writer.beginObject(); + + writer.name( getDataSet().getName() ).beginObject(); + + writer.name( "id" ).value( getDataSet().getName() ); + + writer.name( "category" ).value( getDataSet().getCategory() ); + + writer.name( "description" ).value( getDataSet().getDescription() ); + + writer.name( "index" ).value( getDataSet().getIndex() ); + + writer.name( "thumbnailUrl" ).value( getDataSet().getThumbnailUrl() ); + + writer.name( "datasetUrl" ).value( getDataSet().getDatasetUrl() ); + + writer.endObject(); + + writer.endObject(); + + writer.flush(); + + writer.close(); + + ow.close(); + } + + public void handleXml( final Request baseRequest, final HttpServletResponse response ) throws IOException + { + respondWithString( baseRequest, response, "application/xml", datasetXmlString ); + } + + public void handleBdv( final Request baseRequest, final HttpServletResponse response ) throws IOException + { + String url = baseUrl; + if ( url.endsWith( "/" ) ) + url = url.substring( 0, url.lastIndexOf( "/" ) ); + respondWithString( baseRequest, response, "application/bdv", url ); + } } diff --git a/src/main/java/bdv/server/Constants.java b/src/main/java/bdv/server/Constants.java index 45d56dc..a0b4297 100644 --- a/src/main/java/bdv/server/Constants.java +++ b/src/main/java/bdv/server/Constants.java @@ -6,6 +6,8 @@ public class Constants public static final String MANAGER_CONTEXT_NAME = "manager"; + public static final String DATASET_CONTEXT_NAME = "dataset"; + public static final String[] RESERVED_CONTEXT_NAMES = new String[] { DATASETLIST_CONTEXT_NAME, diff --git a/src/main/java/bdv/server/DataSetContextHandler.java b/src/main/java/bdv/server/DataSetContextHandler.java new file mode 100644 index 0000000..21c1649 --- /dev/null +++ b/src/main/java/bdv/server/DataSetContextHandler.java @@ -0,0 +1,78 @@ +package bdv.server; + +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.log.Log; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; + +/** + * DataSet Handler handles /dataset context + */ +public class DataSetContextHandler extends ServletContextHandler +{ + private static final org.eclipse.jetty.util.log.Logger LOG = Log.getLogger( DataSetContextHandler.class ); + + private final ContextHandlerCollection datasetHandlers; + private final ServletHandler servletHandler; + + public DataSetContextHandler( final ContextHandlerCollection datasetHandlers ) + { + this.datasetHandlers = datasetHandlers; + setContextPath( "/" + Constants.DATASET_CONTEXT_NAME ); + + servletHandler = new ServletHandler(); + Servlet servlet = new DefaultServlet(); + ServletHolder servletHolder = new ServletHolder( servlet ); + servletHandler.addServletWithMapping( servletHolder, "/*.xml" ); + servletHandler.addServletWithMapping( servletHolder, "/*.bdv" ); + + setHandler( _servletHandler ); + } + + @Override + public void doHandle( final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response ) throws IOException, ServletException + { + String datasetName = target; + + if ( datasetName.lastIndexOf( ".xml" ) != -1 ) + { + datasetName = datasetName.substring( 0, datasetName.lastIndexOf( ".xml" ) ); + findCellHandler( datasetName ).handleXml( baseRequest, response ); + } + else if ( datasetName.lastIndexOf( ".bdv" ) != -1 ) + { + datasetName = datasetName.substring( 0, datasetName.lastIndexOf( ".bdv" ) ); + findCellHandler( datasetName ).handleBdv( baseRequest, response ); + } + else + super.doHandle( Constants.DATASET_CONTEXT_NAME + "/" + target, baseRequest, request, response ); + } + + private CellHandler findCellHandler( final String datasetName ) + { + CellHandler found = null; + for ( final Handler handler : datasetHandlers.getChildHandlersByClass( CellHandler.class ) ) + { + final CellHandler contextHandler = ( CellHandler ) handler; + System.out.println( contextHandler ); + if ( contextHandler.getContextPath().equals( getContextPath() + datasetName ) ) + { + found = contextHandler; + break; + } + } + + return found; + } +} diff --git a/src/main/java/bdv/server/IndexPageHandler.java b/src/main/java/bdv/server/IndexPageHandler.java index 422e559..41330a5 100644 --- a/src/main/java/bdv/server/IndexPageHandler.java +++ b/src/main/java/bdv/server/IndexPageHandler.java @@ -118,6 +118,13 @@ public int compare( final DataSet lhs, DataSet rhs ) sb.append( "\t\tCategory: " + ds.getCategory() + "
\n" ); sb.append( "\t\tName: " + ds.getName() + "
\n" ); sb.append( "\t\tDescription: " + ds.getDescription() + "
\n" ); + + String url = ds.getDatasetUrl(); + if ( url.endsWith( "/" ) ) + url = url.substring( 0, url.lastIndexOf( "/" ) ); + + sb.append( "\t\tXML " ); + sb.append( "\t\tBDV
\n" ); sb.append( "\t\n" ); sb.append( "\n" ); } From 5c4d2ee123f52f6a34d8755c89f1fe373e62b9b0 Mon Sep 17 00:00:00 2001 From: HongKee Moon Date: Fri, 22 Apr 2016 18:23:12 +0200 Subject: [PATCH 15/15] Remove logging and use local variable of servletHandler --- src/main/java/bdv/server/DataSetContextHandler.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/bdv/server/DataSetContextHandler.java b/src/main/java/bdv/server/DataSetContextHandler.java index 21c1649..007a2ec 100644 --- a/src/main/java/bdv/server/DataSetContextHandler.java +++ b/src/main/java/bdv/server/DataSetContextHandler.java @@ -24,20 +24,19 @@ public class DataSetContextHandler extends ServletContextHandler private static final org.eclipse.jetty.util.log.Logger LOG = Log.getLogger( DataSetContextHandler.class ); private final ContextHandlerCollection datasetHandlers; - private final ServletHandler servletHandler; public DataSetContextHandler( final ContextHandlerCollection datasetHandlers ) { this.datasetHandlers = datasetHandlers; setContextPath( "/" + Constants.DATASET_CONTEXT_NAME ); - servletHandler = new ServletHandler(); + final ServletHandler servletHandler = new ServletHandler(); Servlet servlet = new DefaultServlet(); ServletHolder servletHolder = new ServletHolder( servlet ); servletHandler.addServletWithMapping( servletHolder, "/*.xml" ); servletHandler.addServletWithMapping( servletHolder, "/*.bdv" ); - setHandler( _servletHandler ); + setHandler( servletHandler ); } @Override @@ -65,7 +64,7 @@ private CellHandler findCellHandler( final String datasetName ) for ( final Handler handler : datasetHandlers.getChildHandlersByClass( CellHandler.class ) ) { final CellHandler contextHandler = ( CellHandler ) handler; - System.out.println( contextHandler ); + if ( contextHandler.getContextPath().equals( getContextPath() + datasetName ) ) { found = contextHandler;