You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2016/08/01 00:08:29 UTC
[40/51] [partial] incubator-juneau git commit: Initial Juno contents
from IBM JazzHub repo
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/CertificateStore.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/CertificateStore.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/CertificateStore.java
new file mode 100755
index 0000000..f06eaf5
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/CertificateStore.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2010, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.deprecated;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.Certificate;
+import java.util.*;
+
+/**
+ * Specialized certificate storage based on {@link KeyStore} for managing trusted certificates.
+ */
+@Deprecated // Use SimpleX509TrustManager
+public class CertificateStore {
+
+ private final KeyStore keyStore;
+
+ /**
+ * Get the underlying KeyStore.
+ */
+ KeyStore getKeyStore() {
+ return keyStore;
+ }
+
+ /**
+ * Helper method that creates a {@link KeyStore} by reading it from a file.
+ */
+ static KeyStore load(File file, String password) throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ try {
+ InputStream input = new FileInputStream(file);
+ try {
+ ks.load(input, password == null ? null : password.toCharArray());
+ } finally {
+ input.close();
+ }
+ } catch (IOException e) {
+ // Return an empty initialized KeyStore
+ ks.load(null, null);
+ }
+ return ks;
+ }
+
+ /**
+ * Helper method that writes a {@link KeyStore} to a file.
+ */
+ static void store(KeyStore ks, File file, String password) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
+ OutputStream output = new FileOutputStream(file);
+ try {
+ ks.store(output, password == null ? null : password.toCharArray());
+ } finally {
+ output.close();
+ }
+ }
+
+ /**
+ * Helper to compute a unique alias within the trust store for a specified certificate.
+ * @param cert The certificate to compute an alias for.
+ */
+ static String computeAlias(Certificate cert) {
+ // There appears to be no standard way to construct certificate aliases,
+ // but this class never depends on looking up a certificate by its
+ // computed alias, so just create an alias that's unique and be done.
+ return UUID.randomUUID().toString();
+ }
+
+ /**
+ * Construct a new TrustStore initially containing no certificates.
+ */
+ public CertificateStore() throws NoSuchAlgorithmException, CertificateException, IOException {
+ try {
+ keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ } catch (KeyStoreException e) {
+ // If the code above caused a KeyStoreException, then the JVM classpath is probably messed up.
+ throw new RuntimeException("KeyStoreException: ["+e.getLocalizedMessage()+"]. "
+ + "Likely cause is that the Java Cryptography Extension libraries are missing from the JRE classpath. "
+ + "Make sure %JAVA_HOME%/lib/ext is specified in your JVM's java.ext.dirs system property.");
+ }
+ keyStore.load(null, null);
+ }
+
+ /**
+ * Does the trust store contain the specified certificate?
+ */
+ public boolean containsCertificate(Certificate cert) throws KeyStoreException {
+ return (keyStore.getCertificateAlias(cert) != null);
+ }
+
+ /**
+ * Enter the specified certificate into the trust store.
+ */
+ public void enterCertificate(Certificate cert) throws KeyStoreException {
+ if (! containsCertificate(cert))
+ keyStore.setCertificateEntry(computeAlias(cert), cert);
+ }
+
+ /*
+ * Helper to copy all the certificate entries, and none of the other
+ * entries, from a {@link KeyStore} into the trust store.
+ */
+ private void enterCertificates(KeyStore ks) throws KeyStoreException {
+ for (Enumeration<String> e = ks.aliases(); e.hasMoreElements();) {
+ String alias = e.nextElement();
+ if (ks.isCertificateEntry(alias)) {
+ Certificate cert = ks.getCertificate(alias);
+ enterCertificate(cert);
+ }
+ }
+ }
+
+ /**
+ * Load the specified {@link KeyStore} file and copy all of the certificates
+ * it contains into the trust store. Only certificates, and not any other
+ * entries, are loaded.
+ */
+ public void loadCertificates(File file, String password) throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
+ KeyStore ks = load(file, password);
+ enterCertificates(ks);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator$Trust.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator$Trust.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator$Trust.class
new file mode 100755
index 0000000..3051b31
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator$Trust.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.class
new file mode 100755
index 0000000..d470011
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.java
new file mode 100755
index 0000000..0ee07e8
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ICertificateValidator.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2010, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.deprecated;
+
+import java.security.cert.*;
+
+/**
+ * Validator of certificates presented by a server when establishing an SSL
+ * connection.
+ */
+@Deprecated // Use SimpleX509TrustManager
+public interface ICertificateValidator {
+
+ /** Action to take for a server-supplied certificate. */
+ public enum Trust {
+
+ /** Do not accept the certificate. */
+ REJECT,
+
+ /** Accept the certificate temporarily for the current connection. */
+ ACCEPT_CONNECTION,
+
+ /** Accept the certificate temporarily for the current session. */
+ ACCEPT_SESSION,
+
+ /** Accept the certificate permanently, by saving it in the user's trust store.*/
+ ACCEPT_PERMANENT
+ }
+
+ /**
+ * There is a problem accepting the server-supplied certificate. What should
+ * be done?
+ *
+ * @param cert The problematic certificate presented by the server
+ * @param problem The {@link CertificateException} that may indicate the specific
+ * problem with the certificate, e.g. {@link CertificateExpiredException}.
+ * @return The disposition on the certificate.
+ */
+ Trust validate(X509Certificate cert, CertificateException problem);
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.class
new file mode 100755
index 0000000..923672e
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.java
new file mode 100755
index 0000000..47256a9
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ITrustStoreProvider.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2010, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.deprecated;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.Certificate;
+
+/**
+ * Utility class for handling certificate stores.
+ */
+@Deprecated // Use SimpleX509TrustManager
+public interface ITrustStoreProvider {
+
+ /**
+ * Returns the store of all certificates trusted for the lifetime
+ * of this trust provider
+ */
+ CertificateStore getSessionTrustStore();
+
+ /**
+ * Returns the store of all permanently trusted certificates.
+ */
+ CertificateStore getRuntimeTrustStore();
+
+ /**
+ * Install a certificate in the user's application-specific on-disk key
+ * store, if possible.
+ */
+ public void installCertificate(Certificate cert) throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.class
new file mode 100755
index 0000000..ad456a0
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.java
new file mode 100755
index 0000000..a12ca43
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/LenientCertificateValidator.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2010, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.deprecated;
+
+import java.security.cert.*;
+
+/**
+ * Lenient certificate validator that always accepts invalid certificates.
+ */
+@Deprecated // Use SimpleX509TrustManager
+public final class LenientCertificateValidator implements ICertificateValidator {
+
+ /** Singleton */
+ public static final ICertificateValidator INSTANCE = new LenientCertificateValidator();
+
+ @Override /* ICertificateValidator */
+ public Trust validate(X509Certificate certificate, CertificateException problem) {
+ return Trust.ACCEPT_CONNECTION;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.class
new file mode 100755
index 0000000..e68e4c7
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.java
new file mode 100755
index 0000000..149302d
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/SharedTrustStoreProvider.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2010, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.deprecated;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.cert.Certificate;
+
+/**
+ * Trust store provider with shared static certificate stores.
+ */
+@Deprecated // Use SimpleX509TrustManager
+public final class SharedTrustStoreProvider implements ITrustStoreProvider {
+
+ // In-memory trust store of all certificates explicitly accepted by the
+ // certificate validator during this session. The validator will not be
+ // called again during this session for any of these certificates. These may
+ // include expired, not yet valid, or otherwise untrusted certificates.
+ // These are kept distinctly, rather than merged into the runtime trust
+ // store, because the base trust manager will never accept expired, etc.
+ // certificates, even if from a trusted source.
+ private static CertificateStore sessionCerts;
+
+ // In-memory trust store of all permanently trusted certificates, assembled
+ // from a number of key store files. These are provided to the base trust
+ // manager as the basis for its decision making.
+ private static CertificateStore runtimeCerts;
+
+ // Location and password of the user's private trust store for this application.
+ private static String userTrustStoreLocation;
+ private static String userTrustStorePassword;
+
+ static {
+ init();
+ }
+
+ private static final void init() {
+ try {
+ String userHome = System.getProperty("user.home");
+ String javaHome = System.getProperty("java.home");
+
+ userTrustStoreLocation = userHome + "/.jazzcerts";
+ userTrustStorePassword = "ibmrationaljazz";
+
+ sessionCerts = new CertificateStore();
+
+ runtimeCerts = new CertificateStore();
+
+ // JRE keystore override
+ String file = System.getProperty("javax.net.ssl.trustStore");
+ String password = System.getProperty("javax.net.ssl.trustStorePassword");
+ addCertificatesFromStore(runtimeCerts, file, password);
+
+ // JRE Signer CA keystore
+ file = javaHome + "/lib/security/cacerts";
+ addCertificatesFromStore(runtimeCerts, file, null);
+
+ // JRE Secure Site CA keystore
+ file = (javaHome + "/lib/security/jssecacerts");
+ addCertificatesFromStore(runtimeCerts, file, null);
+
+ // Application-specific keystore for the current user
+ addCertificatesFromStore(runtimeCerts, userTrustStoreLocation, userTrustStorePassword);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void addCertificatesFromStore(CertificateStore store, String file, String password) {
+ try {
+ File f = new File(file);
+ if (f.canRead())
+ store.loadCertificates(f, password);
+ } catch (Exception e) {
+ // Discard errors
+ }
+ }
+
+ @Override /* ITrustStoreProvider */
+ public CertificateStore getRuntimeTrustStore() {
+ return runtimeCerts;
+ }
+
+ @Override /* ITrustStoreProvider */
+ public CertificateStore getSessionTrustStore() {
+ return sessionCerts;
+ }
+
+ @Override /* ITrustStoreProvider */
+ public void installCertificate(Certificate cert) throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
+ File f = new File(userTrustStoreLocation);
+ KeyStore ks = CertificateStore.load(f, userTrustStorePassword);
+ ks.setCertificateEntry(CertificateStore.computeAlias(cert), cert);
+ CertificateStore.store(ks, f, userTrustStorePassword);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager$1.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager$1.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager$1.class
new file mode 100755
index 0000000..1673c74
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager$1.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.class
new file mode 100755
index 0000000..b06f337
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.java
new file mode 100755
index 0000000..a7539fe
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/deprecated/ValidatingX509TrustManager.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2010, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.deprecated;
+
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+
+import javax.net.ssl.*;
+
+/**
+ * A trust manager that will call a registered {@link ICertificateValidator} in
+ * the event that a problematic (e.g. expired, not yet valid) or untrusted
+ * certificate is presented by a server, and react appropriately. This trust
+ * manager will rely on multiple key stores, and manage one of its own. The
+ * managed key store and the session-accepted key store are shared by all trust
+ * manager instances.
+ */
+@Deprecated // Use SimpleX509TrustManager
+public final class ValidatingX509TrustManager implements X509TrustManager {
+
+ // The JRE-provided trust manager used to validate certificates presented by a server.
+ private X509TrustManager baseTrustManager;
+
+ // The registered certificate validator, may be null, called when the base
+ // trust manager rejects a certificate presented by a server.
+ private ICertificateValidator validator;
+
+ private ITrustStoreProvider trustStoreProvider;
+
+ /**
+ * Construct a new ValidatingX509TrustManager.
+ *
+ * @param validator Certificate validator to consult regarding problematic
+ * certificates, or <code>null</code> to always reject them.
+ */
+ public ValidatingX509TrustManager(ICertificateValidator validator) throws KeyStoreException, NoSuchAlgorithmException {
+ this.validator = validator;
+ this.trustStoreProvider = new SharedTrustStoreProvider();
+
+ // Initialize the base X509 trust manager that will be used to evaluate
+ // certificates presented by the server against the runtime trust store.
+ TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ factory.init(trustStoreProvider.getRuntimeTrustStore().getKeyStore());
+ TrustManager[] managers = factory.getTrustManagers();
+ for (TrustManager manager : managers) {
+ if (manager instanceof X509TrustManager) {
+ baseTrustManager = (X509TrustManager) manager; // Take the first X509TrustManager we find
+ return;
+ }
+ }
+ throw new IllegalStateException("Couldn't find JRE's X509TrustManager"); //$NON-NLS-1$
+ }
+
+ @Override /* X509TrustManager */
+ public X509Certificate[] getAcceptedIssuers() {
+ return baseTrustManager.getAcceptedIssuers();
+ }
+
+ @Override /* X509TrustManager */
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ baseTrustManager.checkClientTrusted(chain, authType);
+ }
+
+ @Override /* X509TrustManager */
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ X509Certificate cert = chain[0];
+
+ // Has the certificate been OK'd for the session?
+ try {
+ if (trustStoreProvider.getSessionTrustStore().containsCertificate(cert))
+ return;
+ } catch (KeyStoreException e) {
+ // Ignore; proceed to try base trust manager
+ }
+
+ try {
+ // Rely on the base trust manager to check the certificate against the assembled runtime key store
+ baseTrustManager.checkServerTrusted(chain, authType);
+ } catch (CertificateException certEx) {
+
+ // Done if there isn't a validator to consult
+ if (validator == null)
+ throw certEx; // Rejected!
+
+ // Ask the registered certificate validator to rule on the certificate
+ ICertificateValidator.Trust disposition = validator.validate(cert, certEx);
+ switch (disposition) {
+ case REJECT: throw certEx;
+ case ACCEPT_CONNECTION: break;
+ case ACCEPT_SESSION: enterCertificate(cert, false); break;
+ case ACCEPT_PERMANENT: enterCertificate(cert, true); break;
+ }
+ }
+ }
+
+ private void enterCertificate(X509Certificate cert, boolean permanent) throws CertificateException {
+ try {
+ trustStoreProvider.getSessionTrustStore().enterCertificate(cert);
+ if (permanent)
+ trustStoreProvider.installCertificate(cert);
+ } catch (KeyStoreException e) {
+ } catch (NoSuchAlgorithmException e) {
+ } catch (IOException e) {
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.class
new file mode 100755
index 0000000..5fc0b7e
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.class differ
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.java
new file mode 100755
index 0000000..58f3017
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/JazzRestClient.java
@@ -0,0 +1,390 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ * The source code for this program is not published or otherwise
+ * divested of its trade secrets, irrespective of what has been
+ * deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.client.jazz;
+
+import static org.apache.http.HttpStatus.*;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import org.apache.http.*;
+import org.apache.http.auth.*;
+import org.apache.http.client.*;
+import org.apache.http.client.config.*;
+import org.apache.http.client.entity.*;
+import org.apache.http.client.methods.*;
+import org.apache.http.impl.client.*;
+import org.apache.http.message.*;
+import org.apache.http.util.*;
+
+import com.ibm.juno.client.*;
+import com.ibm.juno.core.parser.*;
+import com.ibm.juno.core.serializer.*;
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Specialized {@link RestClient} for working with Jazz servers.
+ * <p>
+ * Provides support for BASIC, FORM, and OIDC authentication against Jazz servers and simple SSL certificate validation.
+ *
+ * <h6 class='topic'>Additional Information</h6>
+ * <ul>
+ * <li><a class='doclink' href='package-summary.html#RestClient'>com.ibm.juno.client.jazz > Jazz REST client API</a> for more information and code examples.
+ * </ul>
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public class JazzRestClient extends RestClient {
+
+ private String user, pw;
+ private URI jazzUri;
+ private SSLOpts sslOpts;
+ private String cookie = null;
+
+ /**
+ * Create a new client with no serializer or parser.
+ *
+ * @param jazzUrl The URL of the Jazz server being connected to (e.g. <js>"https://localhost:9443/jazz"</js>)
+ * @param sslOpts SSL options.
+ * @param user The Jazz username.
+ * @param pw The Jazz password.
+ * @throws IOException If a problem occurred trying to authenticate against the Jazz server.
+ */
+ public JazzRestClient(String jazzUrl, SSLOpts sslOpts, String user, String pw) throws IOException {
+ super();
+ this.user = user;
+ this.pw = pw;
+ if (! jazzUrl.endsWith("/"))
+ jazzUrl = jazzUrl + "/";
+ this.sslOpts = sslOpts;
+ jazzUri = URI.create(jazzUrl);
+ }
+
+ /**
+ * Create a new client with no serializer or parser, and LAX SSL support.
+ *
+ * @param jazzUrl The URL of the Jazz server being connected to (e.g. <js>"https://localhost:9443/jazz"</js>)
+ * @param user The Jazz username.
+ * @param pw The Jazz password.
+ * @throws IOException
+ */
+ public JazzRestClient(String jazzUrl, String user, String pw) throws IOException {
+ this(jazzUrl, SSLOpts.LAX, user, pw);
+ }
+
+ /**
+ * Create a new client with the specified serializer and parser instances.
+ *
+ * @param jazzUri The URI of the Jazz server being connected to (e.g. <js>"https://localhost:9443/jazz"</js>)
+ * @param sslOpts SSL options.
+ * @param user The Jazz username.
+ * @param pw The Jazz password.
+ * @param s The serializer for converting POJOs to HTTP request message body text.
+ * @param p The parser for converting HTTP response message body text to POJOs.
+ * @throws IOException If a problem occurred trying to authenticate against the Jazz server.
+ */
+ public JazzRestClient(String jazzUri, SSLOpts sslOpts, String user, String pw, Serializer<?> s, Parser<?> p) throws IOException {
+ this(jazzUri, sslOpts, user, pw);
+ setParser(p);
+ setSerializer(s);
+ }
+
+ /**
+ * Create a new client with the specified serializer and parser instances and LAX SSL support.
+ *
+ * @param jazzUri The URI of the Jazz server being connected to (e.g. <js>"https://localhost:9443/jazz"</js>)
+ * @param user The Jazz username.
+ * @param pw The Jazz password.
+ * @param s The serializer for converting POJOs to HTTP request message body text.
+ * @param p The parser for converting HTTP response message body text to POJOs.
+ * @throws IOException If a problem occurred trying to authenticate against the Jazz server.
+ */
+ public JazzRestClient(String jazzUri, String user, String pw, Serializer<?> s, Parser<?> p) throws IOException {
+ this(jazzUri, SSLOpts.LAX, user, pw);
+ setParser(p);
+ setSerializer(s);
+ }
+
+ /**
+ * Create a new client with the specified serializer and parser classes.
+ *
+ * @param jazzUri The URI of the Jazz server being connected to (e.g. <js>"https://localhost:9443/jazz"</js>)
+ * @param sslOpts SSL options.
+ * @param user The Jazz username.
+ * @param pw The Jazz password.
+ * @param s The serializer for converting POJOs to HTTP request message body text.
+ * @param p The parser for converting HTTP response message body text to POJOs.
+ * @throws IOException If a problem occurred trying to authenticate against the Jazz server.
+ * @throws InstantiationException If serializer or parser could not be instantiated.
+ */
+ public JazzRestClient(String jazzUri, SSLOpts sslOpts, String user, String pw, Class<? extends Serializer<?>> s, Class<? extends Parser<?>> p) throws InstantiationException, IOException {
+ this(jazzUri, sslOpts, user, pw);
+ setParser(p);
+ setSerializer(s);
+ }
+
+ /**
+ * Create a new client with the specified serializer and parser classes and LAX SSL support.
+ *
+ * @param jazzUri The URI of the Jazz server being connected to (e.g. <js>"https://localhost:9443/jazz"</js>)
+ * @param user The Jazz username.
+ * @param pw The Jazz password.
+ * @param s The serializer for converting POJOs to HTTP request message body text.
+ * @param p The parser for converting HTTP response message body text to POJOs.
+ * @throws IOException If a problem occurred trying to authenticate against the Jazz server.
+ * @throws InstantiationException If serializer or parser could not be instantiated.
+ */
+ public JazzRestClient(String jazzUri, String user, String pw, Class<? extends Serializer<?>> s, Class<? extends Parser<?>> p) throws InstantiationException, IOException {
+ this(jazzUri, SSLOpts.LAX, user, pw);
+ setParser(p);
+ setSerializer(s);
+ }
+
+ @Override /* RestClient */
+ protected CloseableHttpClient createHttpClient() throws Exception {
+ try {
+ if (jazzUri.getScheme().equals("https"))
+ enableSSL(sslOpts);
+
+ setRedirectStrategy(new AllowAllRedirects());
+
+ // See wi 368181. The PublicSuffixDomainFilter uses a default PublicSuffixMatcher
+ // that rejects hostnames lacking a dot, such as "ccmserver", so needed
+ // cookies don't get put on outgoing requests.
+ // Here, we create a cookie spec registry with handlers that don't have a PublicSuffixMatcher.
+ if (! Boolean.getBoolean("com.ibm.team.repository.transport.client.useDefaultPublicSuffixMatcher")) { //$NON-NLS-1$
+ // use a lenient PublicSuffixDomainFilter
+ setDefaultCookieSpecRegistry(CookieSpecRegistries.createDefault(null));
+ }
+
+ // We want to use a fresh HttpClientBuilder since the default implementation
+ // uses an unshared PoolingConnectionManager, and if you close the client
+ // and create a new one, can cause a "java.lang.IllegalStateException: Connection pool shut down"
+ CloseableHttpClient client = createHttpClientBuilder().build();
+
+ // Tomcat will respond with SC_BAD_REQUEST (or SC_REQUEST_TIMEOUT?) when the
+ // j_security_check URL is visited before an authenticated URL has been visited.
+ visitAuthenticatedURL(client);
+
+ // Authenticate against the server.
+ String authMethod = determineAuthMethod(client);
+ if (authMethod.equals("FORM")) {
+ formBasedAuthenticate(client);
+ visitAuthenticatedURL(client);
+ } else if (authMethod.equals("BASIC")) {
+ AuthScope scope = new AuthScope(jazzUri.getHost(), jazzUri.getPort());
+ Credentials up = new UsernamePasswordCredentials(user, pw);
+ CredentialsProvider p = new BasicCredentialsProvider();
+ p.setCredentials(scope, up);
+ setDefaultCredentialsProvider(p);
+ client.close();
+ client = getHttpClientBuilder().build();
+ } else if (authMethod.equals("OIDC")) {
+ oidcAuthenticate(client);
+ client.close();
+ client = getHttpClientBuilder().build();
+ }
+
+ return client;
+ } catch (Exception e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override /* RestClient */
+ protected HttpClientBuilder createHttpClientBuilder() {
+ HttpClientBuilder b = super.createHttpClientBuilder();
+
+ // See wi 368181. The PublicSuffixDomainFilter uses a default PublicSuffixMatcher
+ // that rejects hostnames lacking a dot, such as "ccmserver", so needed
+ // cookies don't get put on outgoing requests.
+ // Here, we create a cookie spec registry with handlers that don't have a PublicSuffixMatcher.
+ if (! Boolean.getBoolean("com.ibm.team.repository.transport.client.useDefaultPublicSuffixMatcher"))
+ b.setDefaultCookieSpecRegistry(CookieSpecRegistries.createDefault(null));
+
+ return b;
+ }
+
+
+ /**
+ * Performs form-based authentication against the Jazz server.
+ */
+ private void formBasedAuthenticate(HttpClient client) throws IOException {
+
+ URI uri2 = jazzUri.resolve("j_security_check");
+ HttpPost request = new HttpPost(uri2);
+ request.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+ // Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.
+ request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+
+ NameValuePairs params = new NameValuePairs()
+ .append(new BasicNameValuePair("j_username", user))
+ .append(new BasicNameValuePair("j_password", pw));
+ request.setEntity(new UrlEncodedFormEntity(params));
+
+ HttpResponse response = client.execute(request);
+ try {
+ int rc = response.getStatusLine().getStatusCode();
+
+ Header authMsg = response.getFirstHeader("X-com-ibm-team-repository-web-auth-msg");
+ if (authMsg != null)
+ throw new IOException(authMsg.getValue());
+
+ // The form auth request should always respond with a 200 ok or 302 redirect code
+ if (rc == SC_MOVED_TEMPORARILY) {
+ if (response.getFirstHeader("Location").getValue().matches("^.*/auth/authfailed.*$"))
+ throw new IOException("Invalid credentials.");
+ } else if (rc != SC_OK) {
+ throw new IOException("Unexpected HTTP status: " + rc);
+ }
+ } finally {
+ EntityUtils.consume(response.getEntity());
+ }
+ }
+
+ private void oidcAuthenticate(HttpClient client) throws IOException {
+
+ HttpGet request = new HttpGet(jazzUri);
+ request.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ // Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.
+ request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+
+ HttpResponse response = client.execute(request);
+ try {
+ int code = response.getStatusLine().getStatusCode();
+
+ // Already authenticated
+ if (code == SC_OK)
+ return;
+
+ if (code != SC_UNAUTHORIZED)
+ throw new RestCallException("Unexpected response during OIDC authentication: " + response.getStatusLine());
+
+ //'x-jsa-authorization-redirect'
+ String redirectUri = getHeader(response, "X-JSA-AUTHORIZATION-REDIRECT");
+
+ if (redirectUri == null)
+ throw new RestCallException("Excpected a redirect URI during OIDC authentication: " + response.getStatusLine());
+
+ // Handle Bearer Challenge
+ HttpGet method = new HttpGet(redirectUri + "&prompt=none");
+ addDefaultOidcHeaders(method);
+
+ response = client.execute(method);
+
+ code = response.getStatusLine().getStatusCode();
+
+ if (code != SC_OK)
+ throw new RestCallException("Unexpected response during OIDC authentication phase 2: " + response.getStatusLine());
+
+ String loginRequired = getHeader(response, "X-JSA-LOGIN-REQUIRED");
+
+ if (! "true".equals(loginRequired))
+ throw new RestCallException("X-JSA-LOGIN-REQUIRED header not found on response during OIDC authentication phase 2: " + response.getStatusLine());
+
+ method = new HttpGet(redirectUri + "&prompt=none");
+
+ addDefaultOidcHeaders(method);
+ response = client.execute(method);
+
+ code = response.getStatusLine().getStatusCode();
+
+ if (code != SC_OK)
+ throw new RestCallException("Unexpected response during OIDC authentication phase 3: " + response.getStatusLine());
+
+ // Handle JAS Challenge
+ method = new HttpGet(redirectUri);
+ addDefaultOidcHeaders(method);
+
+ response = client.execute(method);
+
+ code = response.getStatusLine().getStatusCode();
+
+ if (code != SC_OK)
+ throw new RestCallException("Unexpected response during OIDC authentication phase 4: " + response.getStatusLine());
+
+ cookie = getHeader(response, "Set-Cookie");
+
+ Header[] defaultHeaders = new Header[] {
+ new BasicHeader("User-Agent", "Jazz Native Client"),
+ new BasicHeader("X-com-ibm-team-configuration-versions", "com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"),
+ new BasicHeader("Accept", "text/json"),
+ new BasicHeader("Authorization", "Basic " + StringUtils.base64EncodeToString(this.user + ":" + this.pw)),
+ new BasicHeader("Cookie", cookie)
+ };
+
+ setDefaultHeaders(Arrays.asList(defaultHeaders));
+
+ } finally {
+ EntityUtils.consume(response.getEntity());
+ }
+ }
+
+ /*
+ * This is needed for Tomcat because it responds with SC_BAD_REQUEST when the j_security_check URL is visited before an
+ * authenticated URL has been visited. This same URL must also be visited after authenticating with j_security_check
+ * otherwise tomcat will not consider the session authenticated
+ */
+ private int visitAuthenticatedURL(HttpClient httpClient) throws IOException {
+ HttpGet authenticatedURL = new HttpGet(jazzUri.resolve("authenticated/identity"));
+ HttpResponse response = httpClient.execute(authenticatedURL);
+ try {
+ return response.getStatusLine().getStatusCode();
+ } finally {
+ EntityUtils.consume(response.getEntity());
+ }
+ }
+
+ /*
+ * @return Returns "FORM" for form-based authenication, "BASIC" for basic auth, "OIDC" for OIDC. Never <code>null</code>.
+ */
+ private String determineAuthMethod(HttpClient client) throws IOException {
+
+ HttpGet request = new HttpGet(jazzUri.resolve("authenticated/identity"));
+ request.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
+
+ // if the FORM_AUTH_URI path exists, then we know we are using FORM auth
+ HttpResponse response = client.execute(request);
+ try { //'x-jsa-authorization-redirect'
+ Header redirectUri = response.getFirstHeader("X-JSA-AUTHORIZATION-REDIRECT");
+ if (redirectUri != null)
+ return "OIDC";
+
+ int rc = response.getStatusLine().getStatusCode();
+ // Tomcat and Jetty return a status code 200 if the server is using FORM auth
+ if (rc == SC_OK)
+ return "FORM";
+ else if (rc == SC_MOVED_TEMPORARILY && response.getFirstHeader("Location").getValue().matches("^.*(/auth/authrequired|/authenticated/identity).*$"))
+ return "FORM";
+ return "BASIC";
+
+ } finally {
+ EntityUtils.consume(response.getEntity());
+ }
+ }
+
+ private String getHeader(HttpResponse response, String key) {
+ Header h = response.getFirstHeader(key);
+ return (h == null ? null : h.getValue());
+ }
+
+ private void addDefaultOidcHeaders(HttpRequestBase method) {
+ method.addHeader("User-Agent", "Jazz Native Client");
+ method.addHeader("X-com-ibm-team-configuration-versions", "com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0");
+ method.addHeader("Accept", "text/json");
+
+ if (cookie != null) {
+ method.addHeader("Authorization", "Basic " + StringUtils.base64EncodeToString(user + ":" + pw));
+ method.addHeader("Cookie", cookie);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/package.html
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/package.html b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/package.html
new file mode 100755
index 0000000..fce9248
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/jazz/package.html
@@ -0,0 +1,187 @@
+<!DOCTYPE HTML>
+<!--
+ Licensed Materials - Property of IBM
+ (c) Copyright IBM Corporation 2014. All Rights Reserved.
+
+ Note to U.S. Government Users Restricted Rights:
+ Use, duplication or disclosure restricted by GSA ADP Schedule
+ Contract with IBM Corp.
+ -->
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <style type="text/css">
+ /* For viewing in Page Designer */
+ @IMPORT url("../../../../../../javadoc.css");
+
+ /* For viewing in REST interface */
+ @IMPORT url("../htdocs/javadoc.css");
+ body {
+ margin: 20px;
+ }
+ </style>
+ <script>
+ /* Replace all @code and @link tags. */
+ window.onload = function() {
+ document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>');
+ document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>');
+ }
+ </script>
+</head>
+<body>
+<p>Jazz REST client API</p>
+
+<script>
+ function toggle(x) {
+ var div = x.nextSibling;
+ while (div != null && div.nodeType != 1)
+ div = div.nextSibling;
+ if (div != null) {
+ var d = div.style.display;
+ if (d == 'block' || d == '') {
+ div.style.display = 'none';
+ x.className += " closed";
+ } else {
+ div.style.display = 'block';
+ x.className = x.className.replace(/(?:^|\s)closed(?!\S)/g , '' );
+ }
+ }
+ }
+</script>
+
+<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
+<ol class='toc'>
+ <li><p><a class='doclink' href='#RestClient'>Jazz REST client API</a></p>
+</ol>
+
+<!-- ======================================================================================================== -->
+<a id="RestClient"></a>
+<h2 class='topic' onclick='toggle(this)'>1 - Jazz REST client API</h2>
+<div class='topic'>
+ <p>
+ Juno provides a default REST client implementation for working with Jazz servers.
+ The client automatically detects and handles BASIC and FORM authentication and basic certificate authentication.
+ </p>
+ <p>
+ The following code shows the Jazz REST client being used for querying and creating server messages on
+ a Jazz server. The <code>ServerMessage</code> and <code>CreateServerMessage</code> classes
+ are nothing more than simple beans that get serialized over the connection and reconstituted on
+ the server.
+ </p>
+ <p class='bcode'>
+ System.<jsf>out</jsf>.println(<js>"Adding sample messages"</js>);
+
+ DateFormat df = <jk>new</jk> SimpleDateFormat(<js>"yyyy-MM-dd'T'HH:mm:ssZ"</js>);
+ String url = <js>"https://localhost:9443/jazz"</js>;
+ String sms = url + <js>"/serverMessages"</js>;
+ CreateServerMessage m;
+ ServerMessage m2;
+ String s1;
+ ServerMessage[] messages;
+
+ <jc>// Serializer for debug messages.</jc>
+ WriterSerializer serializer = JsonSerializer.<jsf>DEFAULT</jsf>;
+
+ <jc>// Create clients to handle JSON and XML requests and responses.</jc>
+ RestClient jsonClient = <jk>new</jk> JazzRestClient(url, <js>"ADMIN"</js>, <js>"ADMIN"</js>)
+ .setSerializer(JsonSerializer.<jk>class</jk>)
+ .setParser(<jk>new</jk> JsonParser().addFilters(DateFilter.<jsf>ISO8601DTZ</jsf>.<jk>class</jk>));
+
+ RestClient xmlClient = <jk>new</jk> JazzRestClient(url, <js>"ADMIN"</js>, <js>"ADMIN"</js>, XmlSerializer.<jk>class</jk>, XmlParser.<jk>class</jk>);
+
+ <jc>// Delete any existing messages.</jc>
+ messages = jsonClient
+ .doGet(sms)
+ .getResponse(ServerMessage[].<jk>class</jk>);
+
+ <jk>for</jk> (ServerMessage message : messages) {
+ <jk>int</jk> rc = jsonClient
+ .doDelete(message.getUri())
+ .execute();
+ System.<jsf>out</jsf>.println(rc); <jc>// Prints 200.</jc>
+ }
+
+ <jc>// Create an active server message.</jc>
+ m = <jk>new</jk> CreateServerMessage(
+ <jsf>INFO</jsf>,
+ <js>"Test message #1"</js>,
+ <js>"subTypeFoo"</js>,
+ df.parse(<js>"2012-01-01T12:34:56EST"</js>),
+ df.parse(<js>"2013-01-01T12:34:56EST"</js>));
+
+ <jc>// POST the message, get response as string.</jc>
+ s1 = jsonClient
+ .doPost(sms, m)
+ .getResponseAsString();
+ System.<jsf>out</jsf>.println(<js>"TEST1: response="</js> + s1);
+
+ <jc>// POST another message, get response as ServerMessage</jc>
+ m = <jk>new</jk> CreateServerMessage(
+ <jsf>INFO</jsf>,
+ <js>"Test message #2"</js>,
+ <js>"subTypeFoo"</js>,
+ df.parse(<js>"2012-01-01T12:34:56EST"</js>),
+ df.parse(<js>"2013-01-01T12:34:56EST"</js>));
+
+ m2 = jsonClient
+ .doPost(sms, m)
+ .getResponse(ServerMessage.<jk>class</jk>);
+ System.<jsf>out</jsf>.println(<js>"TEST2: response="</js> + serializer.serialize(m2));
+
+ <jc>// Create a future server message.</jc>
+ m = <jk>new</jk> CreateServerMessage(
+ <jsf>INFO</jsf>,
+ <js>"Test message #3"</js>,
+ <js>"subTypeFoo"</js>,
+ df.parse(<js>"2013-01-01T12:34:56EST"</js>),
+ df.parse(<js>"2014-01-01T12:34:56EST"</js>));
+
+ m2 = jsonClient
+ .doPost(sms, m)
+ .getResponse(ServerMessage.<jk>class</jk>);
+ System.<jsf>out</jsf>.println(<js>"TEST3: response="</js> + serializer.serialize(m2));
+ System.<jsf>out</jsf>.println(<js>"TEST3: id="</js> + m2.getItemId().getUuidValue());
+
+ <jc>// Create a future server message using XML on both request and response.</jc>
+ m = <jk>new</jk> CreateServerMessage(
+ <jsf>INFO</jsf>,
+ <js>"Test message #4"</js>,
+ <js>"subTypeFoo"</js>,
+ df.parse(<js>"2013-01-01T12:34:56EST"</js>),
+ df.parse(<js>"2014-01-01T12:34:56EST"</js>));
+
+ s1 = xmlClient
+ .doPost(sms, m)
+ .getResponseAsString();
+ System.<jsf>out</jsf>.println(<js>"TEST4: response="</js> + s1);
+
+ <jc>// Get all the messages</jc>
+ messages = jsonClient
+ .doGet(sms)
+ .getResponse(ServerMessage[].<jk>class</jk>);
+ System.<jsf>out</jsf>.println(<js>"TEST5: response="</js> + serializer.serialize(messages));
+
+ <jc>// Get the first ID</jc>
+ URI firstMessageUrl = messages[0].getUri();
+
+ System.<jsf>out</jsf>.println(<js>"firstMessageUrl=["</js>+firstMessageUrl+<js>"]"</js>);
+
+ <jc>// Get the Date of the first ID.</jc>
+ Date startDate = jsonClient
+ .doGet(firstMessageUrl + <js>"/startDate"</js>)
+ .getResponse(Date.<jk>class</jk>);
+ System.<jsf>out</jsf>.println(<js>"TEST5: response.startDate="</js>+startDate);
+
+ <jc>// Change the start and end dates on first message</jc>
+ m = <jk>new</jk> CreateServerMessage(
+ <jsf>INFO</jsf>,
+ <js>"Test message #3 overwritten"</js>,
+ <js>"subTypeFooBar"</js>,
+ df.parse(<js>"2023-01-01T12:34:56EST"</js>),
+ df.parse(<js>"2024-01-01T12:34:56EST"</js>));
+ s1 = jsonClient.doPut(firstMessageUrl, m).getResponseAsString();
+ System.<jsf>out</jsf>.println(<js>"TEST6: response="</js>+s1);
+ </p>
+</div>
+</body>
+</html>
\ No newline at end of file