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:31 UTC

[42/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.microservice/src/com/ibm/juno/microservice/resources/LogsResource.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/LogsResource.java b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/LogsResource.java
new file mode 100755
index 0000000..8c1a252
--- /dev/null
+++ b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/LogsResource.java
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * � Copyright IBM Corporation 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.microservice.resources;
+
+import static com.ibm.juno.core.html.HtmlDocSerializerProperties.*;
+import static com.ibm.juno.core.html.HtmlSerializerProperties.*;
+import static com.ibm.juno.server.RestServletProperties.*;
+import static javax.servlet.http.HttpServletResponse.*;
+
+import java.io.*;
+import java.net.*;
+import java.nio.charset.*;
+import java.util.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.dto.*;
+import com.ibm.juno.core.filters.*;
+import com.ibm.juno.core.ini.ConfigFile;
+import com.ibm.juno.core.utils.StringUtils;
+import com.ibm.juno.microservice.Resource;
+import com.ibm.juno.server.*;
+import com.ibm.juno.server.annotation.*;
+import com.ibm.juno.server.annotation.Properties;
+import com.ibm.juno.server.converters.Queryable;
+
+/**
+ * REST resource for viewing and accessing log files.
+ */
+@RestResource(
+	path="/logs",
+	label="Log files",
+	description="Log files from this service",
+	properties={
+		@Property(name=HTML_uriAnchorText, value=PROPERTY_NAME),
+		@Property(name=REST_allowMethodParam, value="true")
+	},
+	filters={
+		IteratorFilter.class,       // Allows Iterators and Iterables to be serialized.
+		DateFilter.ISO8601DT.class  // Serialize Date objects as ISO8601 strings.
+	}
+)
+@SuppressWarnings("nls")
+public class LogsResource extends Resource {
+	private static final long serialVersionUID = 1L;
+
+	private ConfigFile cf = getConfig();
+
+	private File logDir = new File(cf.getString("Logging/logDir", "."));
+	private LogEntryFormatter leFormatter = new LogEntryFormatter(
+		cf.getString("Logging/format", "[{date} {level}] {msg}%n"),
+		cf.getString("Logging/dateFormat", "yyyy.MM.dd hh:mm:ss"),
+		cf.getBoolean("Logging/useStackTraceHashes")
+	);
+
+	private final FileFilter filter = new FileFilter() {
+		@Override /* FileFilter */
+		public boolean accept(File f) {
+			return f.isDirectory() || f.getName().endsWith(".log");
+		}
+	};
+
+	/** 
+	 * [GET /*] - Get file details or directory listing. 
+	 * 
+	 * @param req The HTTP request
+	 * @param properties The writable properties for setting the descriptions.
+	 * @param path The log file path.
+	 * @return The log file.
+	 * @throws Exception 
+	 */
+	@RestMethod(name="GET", path="/*", rc={200,404})
+	public Object getFileOrDirectory(RestRequest req, @Properties ObjectMap properties, @PathRemainder String path) throws Exception {
+
+		File f = getFile(path);
+
+		if (f.isDirectory()) {
+			Set<FileResource> l = new TreeSet<FileResource>(new FileResourceComparator());
+			for (File fc : f.listFiles(filter)) {
+				URL fUrl = new URL(req.getTrimmedRequestURL().append('/').append(fc.getName()).toString());
+				l.add(new FileResource(fc, fUrl));
+			}
+			properties.put(HTMLDOC_description, "Contents of " + f.getAbsolutePath());
+			return l;
+		}
+
+		properties.put(HTMLDOC_description, "File details on " + f.getAbsolutePath());
+		return new FileResource(f, new URL(req.getTrimmedRequestURL().toString()));
+	}
+
+	/**
+	 * [VIEW /*] - Retrieve the contents of a log file.
+	 * 
+	 * @param req The HTTP request.
+	 * @param res The HTTP response.
+	 * @param path The log file path.
+	 * @param properties The writable properties for setting the descriptions.
+	 * @param highlight If <code>true</code>, add color highlighting based on severity.
+	 * @param start Optional start timestamp.  Don't print lines logged before the specified timestamp.  Example:  "&start=2014-01-23 11:25:47".
+	 * @param end Optional end timestamp.  Don't print lines logged after the specified timestamp.  Example:  "&end=2014-01-23 11:25:47".
+	 * @param thread Optional thread name filter.  Only show log entries with the specified thread name.  Example: "&thread=pool-33-thread-1".
+	 * @param loggers Optional logger filter.  Only show log entries if they were produced by one of the specified loggers (simple class name).  Example: "&loggers=(LinkIndexService,LinkIndexRestService)".
+	 * @param severity Optional severity filter.  Only show log entries with the specified severity.  Example: "&severity=(ERROR,WARN)".
+	 * @throws Exception 
+	 */
+	@RestMethod(name="VIEW", path="/*", rc={200,404})
+	@SuppressWarnings("nls")
+	public void viewFile(RestRequest req, RestResponse res, @PathRemainder String path, @Properties ObjectMap properties, @Param("highlight") boolean highlight, @Param("start") String start, @Param("end") String end, @Param("thread") String thread, @Param("loggers") String[] loggers, @Param("severity") String[] severity) throws Exception {
+
+		File f = getFile(path);
+		if (f.isDirectory())
+			throw new RestException(SC_METHOD_NOT_ALLOWED, "View not available on directories");
+
+		Date startDate = StringUtils.parseISO8601Date(start), endDate = StringUtils.parseISO8601Date(end);
+
+		if (! highlight) {
+			Object o = getReader(f, startDate, endDate, thread, loggers, severity);
+			res.setContentType("text/plain");
+			if (o instanceof Reader)
+				res.setOutput(o);
+			else {
+				LogParser p = (LogParser)o;
+				Writer w = res.getNegotiatedWriter();
+				try {
+					p.writeTo(w);
+				} finally {
+					w.flush();
+					w.close();
+				}
+			}
+			return;
+		}
+
+		res.setContentType("text/html");
+		PrintWriter w = res.getNegotiatedWriter();
+		try {
+			w.println("<html><body style='font-family:monospace;font-size:8pt;white-space:pre;'>");
+			LogParser lp = getLogParser(f, startDate, endDate, thread, loggers, severity);
+			try {
+				if (! lp.hasNext())
+					w.append("<span style='color:gray'>[EMPTY]</span>");
+				else for (LogParser.Entry le : lp) {
+					char s = le.severity.charAt(0);
+					String color = "black";
+					//SEVERE|WARNING|INFO|CONFIG|FINE|FINER|FINEST
+					if (s == 'I')
+						color = "#006400";
+					else if (s == 'W')
+						color = "#CC8400";
+					else if (s == 'E' || s == 'S')
+						color = "#DD0000";
+					else if (s == 'D' || s == 'F' || s == 'T')
+						color = "#000064";
+					w.append("<span style='color:").append(color).append("'>");
+					le.appendHtml(w).append("</span>");
+				}
+				w.append("</body></html>");
+			} finally {
+				lp.close();
+			}
+		} finally {
+			w.close();
+		}
+	}
+
+	/**
+	 * [VIEW /*] - Retrieve the contents of a log file as parsed entries.
+	 * 
+	 * @param req The HTTP request. 
+	 * @param path The log file path.
+	 * @param start Optional start timestamp.  Don't print lines logged before the specified timestamp.  Example:  "&start=2014-01-23 11:25:47".
+	 * @param end Optional end timestamp.  Don't print lines logged after the specified timestamp.  Example:  "&end=2014-01-23 11:25:47".
+	 * @param thread Optional thread name filter.  Only show log entries with the specified thread name.  Example: "&thread=pool-33-thread-1".
+	 * @param loggers Optional logger filter.  Only show log entries if they were produced by one of the specified loggers (simple class name).  Example: "&loggers=(LinkIndexService,LinkIndexRestService)".
+	 * @param severity Optional severity filter.  Only show log entries with the specified severity.  Example: "&severity=(ERROR,WARN)".
+	 * @return The parsed contents of the log file.
+	 * @throws Exception 
+	 */
+	@RestMethod(name="PARSE", path="/*", converters=Queryable.class, rc={200,404})
+	public LogParser viewParsedEntries(RestRequest req, @PathRemainder String path, @Param("start") String start, @Param("end") String end, @Param("thread") String thread, @Param("loggers") String[] loggers, @Param("severity") String[] severity) throws Exception {
+
+		File f = getFile(path);
+		Date startDate = StringUtils.parseISO8601Date(start), endDate = StringUtils.parseISO8601Date(end);
+
+		if (f.isDirectory())
+			throw new RestException(SC_METHOD_NOT_ALLOWED, "View not available on directories");
+
+		return getLogParser(f, startDate, endDate, thread, loggers, severity);
+	}
+
+	/**
+	 * [DOWNLOAD /*] - Download file.
+	 * 
+	 * @param res The HTTP response. 
+	 * @param path The log file path. 
+	 * @return The contents of the log file.
+	 * @throws Exception 
+	 */
+	@RestMethod(name="DOWNLOAD", path="/*", rc={200,404})
+	public Object downloadFile(RestResponse res, @PathRemainder String path) throws Exception {
+
+		File f = getFile(path);
+
+		if (f.isDirectory())
+			throw new RestException(SC_METHOD_NOT_ALLOWED, "Download not available on directories");
+
+		res.setContentType("application/octet-stream"); //$NON-NLS-1$
+		res.setContentLength((int)f.length());
+		return new FileInputStream(f);
+	}
+
+	/** 
+	 * [DELETE /*] - Delete a file. 
+	 * 
+	 * @param path The log file path. 
+	 * @return A redirect object to the root.
+	 * @throws Exception 
+	 */
+	@RestMethod(name="DELETE", path="/*", rc={200,404})
+	public Object deleteFile(@PathRemainder String path) throws Exception {
+
+		File f = getFile(path);
+
+		if (f.isDirectory())
+			throw new RestException(SC_BAD_REQUEST, "Delete not available on directories.");
+
+		if (f.canWrite())
+			if (! f.delete())
+				throw new RestException(SC_FORBIDDEN, "Could not delete file.");
+
+		return new Redirect(path + "/.."); //$NON-NLS-1$
+	}
+
+	private static BufferedReader getReader(File f) throws IOException {
+		return new BufferedReader(new InputStreamReader(new FileInputStream(f), Charset.defaultCharset()));
+	}
+
+	private File getFile(String path) {
+		if (path != null && path.indexOf("..") != -1)
+			throw new RestException(SC_NOT_FOUND, "File not found.");
+		File f = (path == null ? logDir : new File(logDir.getAbsolutePath() + '/' + path));
+		if (filter.accept(f))
+			return f;
+		throw new RestException(SC_NOT_FOUND, "File not found.");
+	}
+
+	/**
+	 * File bean.
+	 */
+	@SuppressWarnings("javadoc")
+	public static class FileResource {
+		private File f;
+		public String type;
+		public Object name;
+		public Long size;
+		@BeanProperty(filter=DateFilter.Medium.class) public Date lastModified;
+		public URL view, highlighted, parsed, download, delete;
+
+		public FileResource(File f, URL url) throws IOException {
+			this.f = f;
+			this.type = (f.isDirectory() ? "dir" : "file");
+			this.name = f.isDirectory() ? new Link(f.getName(), url.toString()) : f.getName();
+			this.size = f.isDirectory() ? null : f.length();
+			this.lastModified = new Date(f.lastModified());
+			if (f.canRead() && ! f.isDirectory()) {
+				this.view = new URL(url + "?method=VIEW");
+				this.highlighted = new URL(url + "?method=VIEW&highlight=true");
+				this.parsed = new URL(url + "?method=PARSE");
+				this.download = new URL(url + "?method=DOWNLOAD");
+				this.delete = new URL(url + "?method=DELETE");
+			}
+		}
+	}
+
+	private static class FileResourceComparator implements Comparator<FileResource>, Serializable {
+		private static final long serialVersionUID = 1L;
+		@Override /* Comparator */
+		public int compare(FileResource o1, FileResource o2) {
+			int c = o1.type.compareTo(o2.type);
+			return c != 0 ? c : o1.f.getName().compareTo(o2.f.getName());
+		}
+	}
+
+	private Object getReader(File f, final Date start, final Date end, final String thread, final String[] loggers, final String[] severity) throws IOException {
+		if (start == null && end == null && thread == null && loggers == null)
+			return getReader(f);
+		return getLogParser(f, start, end, thread, loggers, severity);
+	}
+
+	private LogParser getLogParser(File f, final Date start, final Date end, final String thread, final String[] loggers, final String[] severity) throws IOException {
+		return new LogParser(leFormatter, f, start, end, thread, loggers, severity);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/SampleRootResource.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/SampleRootResource.java b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/SampleRootResource.java
new file mode 100755
index 0000000..8c60073
--- /dev/null
+++ b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/SampleRootResource.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * � Copyright IBM Corporation 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.microservice.resources;
+
+import com.ibm.juno.microservice.ResourceGroup;
+import com.ibm.juno.server.annotation.RestResource;
+
+/**
+ * Sample root REST resource.
+ * 
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+@RestResource(
+	path="/",
+	label="Sample Root Resource",
+	description="This is a sample router page",
+	children={ConfigResource.class,LogsResource.class}
+)
+public class SampleRootResource extends ResourceGroup {
+	private static final long serialVersionUID = 1L;
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/ShutdownResource.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/ShutdownResource.java b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/ShutdownResource.java
new file mode 100755
index 0000000..e36d51c
--- /dev/null
+++ b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/ShutdownResource.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * � Copyright IBM Corporation 2015. All Rights Reserved.
+ * 
+ * Note to U.S. Government Users Restricted Rights:
+ * Use, duplication or disclosure restricted by GSA ADP Schedule
+ * Contract with IBM Corp. 
+ *******************************************************************************/
+package com.ibm.juno.microservice.resources;
+
+import com.ibm.juno.microservice.Resource;
+import com.ibm.juno.server.annotation.RestMethod;
+import com.ibm.juno.server.annotation.RestResource;
+
+/**
+ * Provides the capability to shut down this REST microservice through a REST call.
+ */
+@RestResource(
+	path="/shutdown",
+	label="Shut down this resource"
+)
+public class ShutdownResource extends Resource {
+	
+	private static final long serialVersionUID = 1L;
+
+	/** 
+	 * [GET /] - Shutdown this resource. 
+	 * 
+	 * @return The string <js>"OK"</js>.
+	 * @throws Exception 
+	 */
+	@RestMethod(name="GET", path="/", description="Show contents of config file.")
+	public String shutdown() throws Exception {
+		new Thread(
+			new Runnable() {
+				@Override /* Runnable */
+				public void run() {
+					try {
+						Thread.sleep(1000);
+					System.exit(0);
+					} catch (InterruptedException e) {
+						e.printStackTrace();
+					}
+				}
+			}
+		).start();
+		return "OK";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/package.html
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/package.html b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/package.html
new file mode 100755
index 0000000..770c4f5
--- /dev/null
+++ b/com.ibm.team.juno.microservice/src/com/ibm/juno/microservice/resources/package.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<!--
+    Licensed Materials - Property of IBM
+    (c) Copyright IBM Corporation 2015. 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");
+		body { 
+			margin: 20px; 
+		}	
+	</style>
+</head>
+<body>
+<p>Predefined Microservice Resources</p>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/.classpath
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/.classpath b/com.ibm.team.juno.releng/.classpath
new file mode 100755
index 0000000..85ebd8a
--- /dev/null
+++ b/com.ibm.team.juno.releng/.classpath
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry exported="true" kind="lib" path="lib/derby/derby.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jaxrs/jsr311-api-1.1.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/javax.servlet_2.5.0.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/commons-codec-1.9/commons-codec-1.9.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/commons-fileupload/org.apache.commons.fileupload_1.3.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/httpclient/commons-logging-1.1.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/httpclient/httpclient-4.5.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/httpclient/httpcomponents-client-4.5-src.zip"/>
+	<classpathentry exported="true" kind="lib" path="lib/httpclient/httpcore-4.4.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/httpclient/httpmime-4.5.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jaxrs/wink-common-1.2.1-incubating.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jaxrs/wink-server-1.2.1-incubating.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jena/jena-core-2.7.1-sources.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jena/jena-core-2.7.1.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jena/jena-iri-0.9.2.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jena/log4j-1.2.16.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jena/slf4j-api-1.6.4.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/jena/slf4j-log4j12-1.6.4.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/junit/hamcrest-core-1.3.jar"/>
+	<classpathentry exported="true" kind="lib" path="lib/junit/junit-4.12.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/.jazzignore
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/.jazzignore b/com.ibm.team.juno.releng/.jazzignore
new file mode 100755
index 0000000..f8f7ec4
--- /dev/null
+++ b/com.ibm.team.juno.releng/.jazzignore
@@ -0,0 +1,37 @@
+### Jazz Ignore 0
+# Ignored files and folders will not be committed, but may be modified during 
+# accept or update.  
+# - Ignore properties should contain a space separated list of filename patterns.  
+# - Each pattern is case sensitive and surrounded by braces ('{' and '}').  
+# - "*" matches zero or more characters.  
+# - "?" matches a single character.  
+# - The pattern list may be split across lines by ending the line with a 
+#     backslash and starting the next line with a tab.  
+# - Patterns in core.ignore prevent matching resources in the same 
+#     directory from being committed.  
+# - Patterns in core.ignore.recursive matching resources in the current 
+#     directory and all subdirectories from being committed.  
+# - The default value of core.ignore.recursive is *.class 
+# - The default value for core.ignore is bin 
+# 
+# To ignore shell scripts and hidden files in this subtree: 
+#     e.g: core.ignore.recursive = {*.sh} {\.*} 
+# 
+# To ignore resources named 'bin' in the current directory (but allow 
+#  them in any sub directorybelow): 
+#     e.g: core.ignore = {bin} 
+# 
+# NOTE: modifying ignore files will not change the ignore status of 
+#     Eclipse derived resources.
+
+core.ignore.recursive= \
+	{*.class} 
+
+core.ignore= \
+	{CT_Results} \
+	{CT_Results_html} \
+	{bin} \
+	{build} \
+	{doc} \
+	{docstage} \
+	{temp.build} 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/.project
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/.project b/com.ibm.team.juno.releng/.project
new file mode 100755
index 0000000..4b21cbb
--- /dev/null
+++ b/com.ibm.team.juno.releng/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>com.ibm.team.juno.releng</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.ManifestBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.pde.SchemaBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.pde.PluginNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/.settings/org.eclipse.jdt.core.prefs b/com.ibm.team.juno.releng/.settings/org.eclipse.jdt.core.prefs
new file mode 100755
index 0000000..9370afe
--- /dev/null
+++ b/com.ibm.team.juno.releng/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,25 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=disabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
+org.eclipse.jdt.core.compiler.source=1.6

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/Juno+SW+Classification+Guidance+&+Questionnaire [v1].doc
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/Juno+SW+Classification+Guidance+&+Questionnaire [v1].doc b/com.ibm.team.juno.releng/Juno+SW+Classification+Guidance+&+Questionnaire [v1].doc
new file mode 100755
index 0000000..dea703b
Binary files /dev/null and b/com.ibm.team.juno.releng/Juno+SW+Classification+Guidance+&+Questionnaire [v1].doc differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/META-INF/MANIFEST.MF b/com.ibm.team.juno.releng/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..6e3c020
--- /dev/null
+++ b/com.ibm.team.juno.releng/META-INF/MANIFEST.MF
@@ -0,0 +1,40 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Juno Releng
+Bundle-SymbolicName: com.ibm.team.juno.releng
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: IBM
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ClassPath: 
+ lib/derby/derby.jar,
+ lib/jaxrs/jsr311-api-1.1.1.jar,
+ lib/httpclient/httpclient-4.5.jar,
+ lib/httpclient/httpmime-4.5.jar,
+ lib/httpclient/httpcore-4.4.1.jar
+Export-Package: 
+ org.apache.derby.jdbc,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ javax.ws.rs.ext,
+ org.apache.http,
+ org.apache.http.auth,
+ org.apache.http.client,
+ org.apache.http.client.config,
+ org.apache.http.client.entity,
+ org.apache.http.client.methods,
+ org.apache.http.client.params,
+ org.apache.http.client.utils,
+ org.apache.http.config,
+ org.apache.http.conn,
+ org.apache.http.conn.scheme,
+ org.apache.http.conn.ssl,
+ org.apache.http.conn.socket,
+ org.apache.http.entity,
+ org.apache.http.entity.mime,
+ org.apache.http.impl.client,
+ org.apache.http.impl.conn,
+ org.apache.http.impl.cookie,
+ org.apache.http.message,
+ org.apache.http.params,
+ org.apache.http.protocol,
+ org.apache.http.util

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/Readme.txt
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/Readme.txt b/com.ibm.team.juno.releng/Readme.txt
new file mode 100755
index 0000000..0c2facd
--- /dev/null
+++ b/com.ibm.team.juno.releng/Readme.txt
@@ -0,0 +1,33 @@
+#================================================================================
+# Juno Components List
+#================================================================================
+
+---------------------------------------------------------------------------------
+juno-all.jar
+Contains all binaries from the Core, Server, Client, and Microservice APIs
+---------------------------------------------------------------------------------
+
+---------------------------------------------------------------------------------
+bundles/*
+Contents of juno-all.jar as individual OSGi bundles.
+---------------------------------------------------------------------------------
+
+---------------------------------------------------------------------------------
+source/*
+Same as the binaries, except includes all the source code as well.
+---------------------------------------------------------------------------------
+
+---------------------------------------------------------------------------------
+juno-javadocs.war
+The docs for everything.
+---------------------------------------------------------------------------------
+
+---------------------------------------------------------------------------------
+microservice-project.zip
+The Eclipse project template for creating a microservice.
+---------------------------------------------------------------------------------
+
+---------------------------------------------------------------------------------
+microservice-samples-project.zip
+The Eclipse project for running the samples.
+---------------------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/all/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/all/META-INF/MANIFEST.MF b/com.ibm.team.juno.releng/bin/all/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..f8481cf
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/all/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Ant-Version: Apache Ant 1.8.3
+Created-By: pwa6470_27sr1-20140411_01 (SR1) (IBM Corporation)
+Built-By: jbognar
+Build-Date: December 30 2015
+Bundle-Name: Juno Cloud API
+Bundle-Vendor: IBM
+Bundle-SymbolicName: com.ibm.team.juno.all
+Bundle-Version: 5.2.0.0
+

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/META-INF/MANIFEST.MF b/com.ibm.team.juno.releng/bin/client/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..6c9827b
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/META-INF/MANIFEST.MF
@@ -0,0 +1,24 @@
+Manifest-Version: 1.0
+Ant-Version: Apache Ant 1.8.3
+Created-By: pwa6470_27sr1-20140411_01 (SR1) (IBM Corporation)
+Bundle-ManifestVersion: 2
+Bundle-Name: Juno Cloud API - Client
+Bundle-SymbolicName: com.ibm.team.juno.client
+Bundle-Version: 5.2.0.0
+Bundle-Vendor: IBM
+Require-Bundle: com.ibm.team.juno
+Import-Package: org.apache.http,org.apache.http.auth,org.apache.http.c
+ lient,org.apache.http.client.config,org.apache.http.client.entity,org
+ .apache.http.client.methods,org.apache.http.client.params,org.apache.
+ http.client.utils,org.apache.http.config,org.apache.http.conn,org.apa
+ che.http.conn.routing,org.apache.http.conn.scheme,org.apache.http.con
+ n.socket,org.apache.http.conn.ssl,org.apache.http.conn.util,org.apach
+ e.http.cookie,org.apache.http.entity,org.apache.http.impl.client,org.
+ apache.http.impl.conn,org.apache.http.impl.cookie,org.apache.http.mes
+ sage,org.apache.http.params,org.apache.http.protocol,org.apache.http.
+ util
+Export-Package: com.ibm.juno.client,com.ibm.juno.client.jazz
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Built-By: jbognar
+Build-Date: December 30 2015
+

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.class
new file mode 100755
index 0000000..42defb1
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.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/AllowAllRedirects.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.java
new file mode 100755
index 0000000..7f68ef0
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/AllowAllRedirects.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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;
+
+import org.apache.http.impl.client.*;
+
+/**
+ * Redirect strategy that allows for redirects on any request type, not just <code>GET</code> or <code>HEAD</code>.
+ * <p>
+ * Note:  This class is similar to <code>org.apache.http.impl.client.LaxRedirectStrategy</code>
+ * 	in Apache HttpClient 4.2, but also allows for redirects on <code>PUTs</code> and <code>DELETEs</code>.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public class AllowAllRedirects extends DefaultRedirectStrategy {
+
+   @Override /* DefaultRedirectStrategy */
+   protected boolean isRedirectable(final String method) {
+   	return true;
+   }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.class
new file mode 100755
index 0000000..f83558b
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.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/DateHeader.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.java
new file mode 100755
index 0000000..47247d5
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/DateHeader.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014. 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;
+
+import java.util.*;
+
+import org.apache.http.client.utils.*;
+import org.apache.http.message.*;
+
+/**
+ * Convenience class for setting date headers in RFC2616 format.
+ * <p>
+ * Equivalent to the following code:
+ * <p class='bcode'>
+ * 	Header h = <jk>new</jk> Header(name, DateUtils.<jsm>formatDate</jsm>(value));
+ * </p>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class DateHeader extends BasicHeader {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Creates a date request property in RFC2616 format.
+	 *
+	 * @param name The header name.
+	 * @param value The header value.
+	 */
+	public DateHeader(String name, Date value) {
+		super(name, DateUtils.formatDate(value));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.class
new file mode 100755
index 0000000..45e2b0c
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.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/HttpMethod.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.java
new file mode 100755
index 0000000..773ada1
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/HttpMethod.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 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;
+
+/**
+ * Enumeration of HTTP methods.
+ * <p>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public enum HttpMethod {
+
+	/** HTTP GET */
+	GET(false),
+
+	/** HTTP PUT */
+	PUT(true),
+
+	/** HTTP POST */
+	POST(true),
+
+	/** HTTP DELETE */
+	DELETE(false),
+
+	/** HTTP OPTIONS */
+	OPTIONS(false),
+
+	/** HTTP HEAD */
+	HEAD(false),
+
+	/** HTTP TRACE */
+	TRACE(false),
+
+	/** HTTP CONNECT */
+	CONNECT(false),
+
+	/** HTTP MOVE */
+	MOVE(false);
+
+	private boolean hasContent;
+
+	HttpMethod(boolean hasContent) {
+		this.hasContent = hasContent;
+	}
+
+	/**
+	 * Returns whether this HTTP method normally has content.
+	 *
+	 * @return <jk>true</jk> if this HTTP method normally has content.
+	 */
+	public boolean hasContent() {
+		return hasContent;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.class
new file mode 100755
index 0000000..3373a82
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.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/NameValuePairs.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.java
new file mode 100755
index 0000000..9e6e65b
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/NameValuePairs.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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;
+
+import java.util.*;
+
+import org.apache.http.*;
+import org.apache.http.client.entity.*;
+
+/**
+ * Convenience class for constructing instances of <code>List&lt;NameValuePair&gt;</code>
+ * 	for the {@link UrlEncodedFormEntity} class.
+ *
+ * <h6 class='topic'>Example</h6>
+ * <p class='bcode'>
+ * 	NameValuePairs params = <jk>new</jk> NameValuePairs()
+ * 		.append(<jk>new</jk> BasicNameValuePair(<js>"j_username"</js>, user))
+ * 		.append(<jk>new</jk> BasicNameValuePair(<js>"j_password"</js>, pw));
+ * 	request.setEntity(<jk>new</jk> UrlEncodedFormEntity(params));
+ * </p>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class NameValuePairs extends LinkedList<NameValuePair> {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Appends the specified pair to the end of this list.
+	 *
+	 * @param pair The pair to append to this list.
+	 * @return This object (for method chaining).
+	 */
+	public NameValuePairs append(NameValuePair pair) {
+		super.add(pair);
+		return this;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.class
new file mode 100755
index 0000000..6d36243
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.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/ResponsePattern.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.java
new file mode 100755
index 0000000..a10e939
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/ResponsePattern.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 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;
+
+import java.io.*;
+import java.util.regex.*;
+
+/**
+ * Used to find regular expression matches in REST responses made through {@link RestCall}.
+ * <p>
+ * Response patterns are applied to REST calls through the {@link RestCall#addResponsePattern(ResponsePattern)} method.
+ * <p>
+ * <h6 class='topic'>Example</h6>
+ * This example shows how to use a response pattern finder to find and capture patterns for <js>"x=number"</js> and <js>"y=string"</js>
+ * 	from a response body.
+ * <p>
+ * <p class='bcode'>
+ * 	<jk>final</jk> List&lt;Number&gt; xList = <jk>new</jk> ArrayList&lt;Number&gt;();
+ * 	<jk>final</jk> List&lt;String&gt; yList = <jk>new</jk> ArrayList&lt;String&gt;();
+ *
+ * 	restClient.doGet(<jsf>URL</jsf>)
+ * 		.addResponsePattern(
+ * 			<jk>new</jk> ResponsePattern(<js>"x=(\\d+)"</js>) {
+ * 				<ja>@Override</ja>
+ * 				<jk>public void</jk> onMatch(RestCall restCall, Matcher m) <jk>throws</jk> RestCallException {
+ * 					xList.add(Integer.<jsm>parseInt</jsm>(m.group(1)));
+ * 				}
+ * 				<ja>@Override</ja>
+ * 				<jk>public void</jk> onNoMatch(RestCall restCall) <jk>throws</jk> RestCallException {
+ * 					<jk>throw new</jk> RestCallException(<js>"No X's found!"</js>);
+ * 				}
+ * 			}
+ * 		)
+ * 		.addResponsePattern(
+ * 			<jk>new</jk> ResponsePattern(<js>"y=(\\S+)"</js>) {
+ * 				<ja>@Override</ja>
+ * 				<jk>public void</jk> onMatch(RestCall restCall, Matcher m) <jk>throws</jk> RestCallException {
+ * 					yList.add(m.group(1));
+ * 				}
+ * 				<ja>@Override</ja>
+ * 				<jk>public void</jk> onNoMatch(RestCall restCall) <jk>throws</jk> RestCallException {
+ * 					<jk>throw new</jk> RestCallException(<js>"No Y's found!"</js>);
+ * 				}
+ * 			}
+ * 		)
+ * 		.run();
+ * </p>
+ * <p>
+ * <h5 class='notes'>Important Notes:</h5>
+ * <ol class='notes'>
+ * 	<li><p>
+ * 		Using response patterns does not affect the functionality of any of the other methods
+ * 		used to retrieve the response such as {@link RestCall#getResponseAsString()} or {@link RestCall#getResponse(Class)}.<br>
+ * 		HOWEVER, if you want to retrieve the entire text of the response from inside the match methods,
+ * 		use {@link RestCall#getCapturedResponse()} since this method will not absorb the response for those other methods.
+ * 	</p>
+ * 	<li><p>
+ * 		Response pattern methods are NOT executed if a REST exception occurs during the request.
+ * 	</p>
+ * 	<li><p>
+ * 		The {@link RestCall#successPattern(String)} and {@link RestCall#failurePattern(String)} methods use instances of
+ * 		this class to throw {@link RestCallException RestCallExceptions} when success patterns are not found or failure patterns
+ * 		are found.
+ * 	</p>
+ * 	<li><p>
+ * 		{@link ResponsePattern} objects are reusable and thread-safe.
+ * 	</p>
+ * </ol>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public abstract class ResponsePattern {
+
+	private Pattern pattern;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param pattern Regular expression pattern.
+	 */
+	public ResponsePattern(String pattern) {
+		this.pattern = Pattern.compile(pattern);
+	}
+
+	void match(RestCall rc) throws RestCallException {
+		try {
+			Matcher m = pattern.matcher(rc.getCapturedResponse());
+			boolean found = false;
+			while (m.find()) {
+				onMatch(rc, m);
+				found = true;
+			}
+			if (! found)
+				onNoMatch(rc);
+		} catch (IOException e) {
+			throw new RestCallException(e);
+		}
+	}
+
+	/**
+	 * Returns the pattern passed in through the constructor.
+	 *
+	 * @return The pattern passed in through the constructor.
+	 */
+	protected String getPattern() {
+		return pattern.pattern();
+	}
+
+	/**
+	 * Instances can override this method to handle when a regular expression pattern matches
+	 * 	on the output.
+	 * <p>
+	 * This method is called once for every pattern match that occurs in the response text.
+	 *
+	 * @param rc The {@link RestCall} that this pattern finder is being used on.
+	 * @param m The regular expression {@link Matcher}.  Can be used to retrieve group matches in the pattern.
+	 * @throws RestCallException Instances can throw an exception if a failure condition is detected.
+	 */
+	public void onMatch(RestCall rc, Matcher m) throws RestCallException {}
+
+	/**
+	 * Instances can override this method to handle when a regular expression pattern doesn't match on the output.
+	 *
+	 * @param rc The {@link RestCall} that this pattern finder is being used on.
+	 * @throws RestCallException Instances can throw an exception if a failure condition is detected.
+	 */
+	public void onNoMatch(RestCall rc) throws RestCallException {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$1.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$1.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$1.class
new file mode 100755
index 0000000..3a5e0e9
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$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/RestCall$2.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$2.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$2.class
new file mode 100755
index 0000000..711dec8
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$2.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/RestCall$3.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$3.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$3.class
new file mode 100755
index 0000000..60f20dd
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall$3.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/RestCall.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall.class
new file mode 100755
index 0000000..cbdd200
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall.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/RestCall.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall.java b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall.java
new file mode 100755
index 0000000..67cbff2
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCall.java
@@ -0,0 +1,942 @@
+/*******************************************************************************
+ * 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;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.logging.*;
+import java.util.regex.*;
+
+import org.apache.http.*;
+import org.apache.http.client.*;
+import org.apache.http.client.config.*;
+import org.apache.http.client.methods.*;
+import org.apache.http.impl.client.*;
+import org.apache.http.util.*;
+
+import com.ibm.juno.core.*;
+import com.ibm.juno.core.encoders.*;
+import com.ibm.juno.core.parser.*;
+import com.ibm.juno.core.parser.ParseException;
+import com.ibm.juno.core.serializer.*;
+import com.ibm.juno.core.utils.*;
+
+/**
+ * Represents a connection to a remote REST resource.
+ * <p>
+ * 	Instances of this class are created by the various {@code doX()} methods on the {@link RestClient} class.
+ * <p>
+ * 	This class uses only Java standard APIs.  Requests can be built up using a fluent interface with method chaining, like so...
+ *
+ * <p class='bcode'>
+ * 	RestClient client = <jk>new</jk> RestClient();
+ * 	RestCall c = client.doPost(<jsf>URL</jsf>).setInput(o).setHeader(x,y);
+ * 	MyBean b = c.getResponse(MyBean.<jk>class</jk>);
+ * </p>
+ * <p>
+ * 	The actual connection and request/response transaction occurs when calling one of the <code>getResponseXXX()</code> methods.
+ *
+ * <h6 class='topic'>Additional Information</h6>
+ * <ul>
+ * 	<li><a class='doclink' href='package-summary.html#RestClient'>com.ibm.juno.client &gt; REST client API</a> for more information and code examples.
+ * </ul>
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class RestCall {
+
+	private final RestClient client;                       // The client that created this call.
+	private final HttpRequestBase request;                 // The request.
+	private HttpResponse response;                         // The response.
+	private List<RestCallInterceptor> interceptors = new ArrayList<RestCallInterceptor>();               // Used for intercepting and altering requests.
+
+	private boolean isConnected = false;                   // connect() has been called.
+	private boolean allowRedirectsOnPosts;
+	private int retries = 1;
+	private int redirectOnPostsTries = 5;
+	private long retryInterval = -1;
+	private RetryOn retryOn = RetryOn.DEFAULT;
+	private boolean ignoreErrors;
+	private boolean byLines = false;
+	private TeeWriter writers = new TeeWriter();
+	private StringWriter capturedResponseWriter;
+	private String capturedResponse;
+	private TeeOutputStream outputStreams = new TeeOutputStream();
+	private boolean isClosed = false;
+	private boolean isFailed = false;
+
+	/**
+	 * Constructs a REST call with the specified method name.
+	 *
+	 * @param client The client that created this request.
+	 * @param request The wrapped Apache HTTP client request object.
+	 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
+	 */
+	protected RestCall(RestClient client, HttpRequestBase request) throws RestCallException {
+		this.client = client;
+		this.request = request;
+		for (RestCallInterceptor i : this.client.interceptors)
+			addInterceptor(i);
+	}
+
+	/**
+	 * Sets the input for this REST call.
+	 *
+	 * @param input The input to be sent to the REST resource (only valid for PUT and POST) requests. <br>
+	 * 	Can be of the following types:
+	 * 	<ul>
+	 * 		<li>{@link Reader} - Raw contents of {@code Reader} will be serialized to remote resource.
+	 * 		<li>{@link InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
+	 * 		<li>{@link Object} - POJO to be converted to text using the {@link Serializer} registered with the {@link RestClient}.
+	 * 		<li>{@link HttpEntity} - Bypass Juno serialization and pass HttpEntity directly to HttpClient.
+	 * 	</ul>
+	 * @return This object (for method chaining).
+	 * @throws RestCallException If a retry was attempted, but the entity was not repeatable.
+	 */
+	public RestCall setInput(final Object input) throws RestCallException {
+		if (! (request instanceof HttpEntityEnclosingRequestBase))
+			throw new RestCallException(0, "Method does not support content entity.", request.getMethod(), request.getURI(), null);
+		HttpEntity entity = (input instanceof HttpEntity ? (HttpEntity)input : new RestRequestEntity(input, client.serializer));
+		((HttpEntityEnclosingRequestBase)request).setEntity(entity);
+		if (retries > 1 && ! entity.isRepeatable())
+			throw new RestCallException("Rest call set to retryable, but entity is not repeatable.");
+		return this;
+	}
+
+	/**
+	 * Convenience method for setting a header value on the request.
+	 * <p>
+	 * Equivalent to calling <code>restCall.getRequest().setHeader(name, value.toString())</code>.
+	 *
+	 * @param name The header name.
+	 * @param value The header value.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall setHeader(String name, Object value) {
+		request.setHeader(name, value.toString());
+		return this;
+	}
+
+	/**
+	 * Make this call retryable if an error response (>=400) is received.
+	 *
+	 * @param retries The number of retries to attempt.
+	 * @param interval The time in milliseconds between attempts.
+	 * @param retryOn Optional object used for determining whether a retry should be attempted.
+	 * 	If <jk>null</jk>, uses {@link RetryOn#DEFAULT}.
+	 * @return This object (for method chaining).
+	 * @throws RestCallException If current entity is not repeatable.
+	 */
+	public RestCall setRetryable(int retries, long interval, RetryOn retryOn) throws RestCallException {
+		if (request instanceof HttpEntityEnclosingRequestBase) {
+		HttpEntity e = ((HttpEntityEnclosingRequestBase)request).getEntity();
+		if (e != null && ! e.isRepeatable())
+			throw new RestCallException("Attempt to make call retryable, but entity is not repeatable.");
+		}
+		this.retries = retries;
+		this.retryInterval = interval;
+		this.retryOn = (retryOn == null ? RetryOn.DEFAULT : retryOn);
+		return this;
+
+	}
+
+	/**
+	 * For this call, allow automatic redirects when a 302 or 307 occurs when
+	 * 	performing a POST.
+	 * <p>
+	 * Note that this can be inefficient since the POST body needs to be serialized
+	 * 	twice.
+	 * The preferred approach if possible is to use the {@link LaxRedirectStrategy} strategy
+	 * 	on the underlying HTTP client.  However, this method is provided if you don't
+	 * 	have access to the underlying client.
+	 *
+	 * @param b Redirect flag.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall allowRedirectsOnPosts(boolean b) {
+		this.allowRedirectsOnPosts = b;
+		return this;
+	}
+
+	/**
+	 * Specify the number of redirects to follow before throwing an exception.
+	 *
+	 * @param maxAttempts Allow a redirect to occur this number of times.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall setRedirectMaxAttempts(int maxAttempts) {
+		this.redirectOnPostsTries = maxAttempts;
+		return this;
+	}
+
+	/**
+	 * Add an interceptor for this call only.
+	 *
+	 * @param interceptor The interceptor to add to this call.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall addInterceptor(RestCallInterceptor interceptor) {
+		interceptors.add(interceptor);
+		interceptor.onInit(this);
+		return this;
+	}
+
+	/**
+	 * Pipes the request output to the specified writer when {@link #run()} is called.
+	 * <p>
+	 * The writer is not closed.
+	 * <p>
+	 * This method can be called multiple times to pipe to multiple writers.
+	 *
+	 * @param w The writer to pipe the output to.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall pipeTo(Writer w) {
+		return pipeTo(w, false);
+	}
+
+	/**
+	 * Pipe output from response to the specified writer when {@link #run()} is called.
+	 * <p>
+	 * This method can be called multiple times to pipe to multiple writers.
+	 *
+	 * @param w The writer to write the output to.
+	 * @param close Close the writer when {@link #close()} is called.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall pipeTo(Writer w, boolean close) {
+		return pipeTo(null, w, close);
+	}
+
+	/**
+	 * Pipe output from response to the specified writer when {@link #run()} is called and associate
+	 * that writer with an ID so it can be retrieved through {@link #getWriter(String)}.
+	 * <p>
+	 * This method can be called multiple times to pipe to multiple writers.
+	 *
+	 * @param id A string identifier that can be used to retrieve the writer using {@link #getWriter(String)}
+	 * @param w The writer to write the output to.
+	 * @param close Close the writer when {@link #close()} is called.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall pipeTo(String id, Writer w, boolean close) {
+		writers.add(id, w, close);
+		return this;
+	}
+
+	/**
+	 * Retrieves a writer associated with an ID via {@link #pipeTo(String, Writer, boolean)}
+	 *
+	 * @param id A string identifier that can be used to retrieve the writer using {@link #getWriter(String)}
+	 * @return The writer, or <jk>null</jk> if no writer is associated with that ID.
+	 */
+	public Writer getWriter(String id) {
+		return writers.getWriter(id);
+	}
+
+	/**
+	 * When output is piped to writers, flush the writers after every line of output.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public RestCall byLines() {
+		this.byLines = true;
+		return this;
+	}
+
+	/**
+	 * Pipes the request output to the specified output stream when {@link #run()} is called.
+	 * <p>
+	 * The output stream is not closed.
+	 * <p>
+	 * This method can be called multiple times to pipe to multiple output streams.
+	 *
+	 * @param os The output stream to pipe the output to.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall pipeTo(OutputStream os) {
+		return pipeTo(os, false);
+	}
+
+	/**
+	 * Pipe output from response to the specified output stream when {@link #run()} is called.
+	 * <p>
+	 * This method can be called multiple times to pipe to multiple output stream.
+	 *
+	 * @param os The output stream to write the output to.
+	 * @param close Close the output stream when {@link #close()} is called.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall pipeTo(OutputStream os, boolean close) {
+		return pipeTo(null, os, close);
+	}
+
+	/**
+	 * Pipe output from response to the specified output stream when {@link #run()} is called and associate
+	 * that output stream with an ID so it can be retrieved through {@link #getOutputStream(String)}.
+	 * <p>
+	 * This method can be called multiple times to pipe to multiple output stream.
+	 *
+	 * @param id A string identifier that can be used to retrieve the output stream using {@link #getOutputStream(String)}
+	 * @param os The output stream to write the output to.
+	 * @param close Close the output stream when {@link #close()} is called.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall pipeTo(String id, OutputStream os, boolean close) {
+		outputStreams.add(id, os, close);
+		return this;
+	}
+
+	/**
+	 * Retrieves an output stream associated with an ID via {@link #pipeTo(String, OutputStream, boolean)}
+	 *
+	 * @param id A string identifier that can be used to retrieve the writer using {@link #getWriter(String)}
+	 * @return The writer, or <jk>null</jk> if no writer is associated with that ID.
+	 */
+	public OutputStream getOutputStream(String id) {
+		return outputStreams.getOutputStream(id);
+	}
+
+	/**
+	 * Prevent {@link RestCallException RestCallExceptions} from being thrown when HTTP status 400+ is encountered.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall ignoreErrors() {
+		this.ignoreErrors = true;
+		return this;
+	}
+
+	/**
+	 * Stores the response text so that it can later be captured using {@link #getCapturedResponse()}.
+	 * <p>
+	 * This method should only be called once.  Multiple calls to this method are ignored.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public RestCall captureResponse() {
+		if (capturedResponseWriter == null) {
+			capturedResponseWriter = new StringWriter();
+			writers.add(capturedResponseWriter, false);
+		}
+		return this;
+	}
+
+
+	/**
+	 * Look for the specified regular expression pattern in the response output.
+	 * <p>
+	 * Causes a {@link RestCallException} to be thrown if the specified pattern is found in the output.
+	 * <p>
+	 * This method uses {@link #getCapturedResponse()} to read the response text and so does not affect the other output
+	 * 	methods such as {@link #getResponseAsString()}.
+	 *
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	<jc>// Throw a RestCallException if FAILURE or ERROR is found in the output.</jc>
+	 * 	restClient.doGet(<jsf>URL</jsf>)
+	 * 		.failurePattern(<js>"FAILURE|ERROR"</js>)
+	 * 		.run();
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param errorPattern A regular expression to look for in the response output.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall failurePattern(final String errorPattern) {
+		addResponsePattern(
+			new ResponsePattern(errorPattern) {
+				@Override
+				public void onMatch(RestCall rc, Matcher m) throws RestCallException {
+					throw new RestCallException("Failure pattern detected.");
+				}
+			}
+		);
+		return this;
+	}
+
+	/**
+	 * Look for the specified regular expression pattern in the response output.
+	 * <p>
+	 * Causes a {@link RestCallException} to be thrown if the specified pattern is not found in the output.
+	 * <p>
+	 * This method uses {@link #getCapturedResponse()} to read the response text and so does not affect the other output
+	 * 	methods such as {@link #getResponseAsString()}.
+	 *
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	<jc>// Throw a RestCallException if SUCCESS is not found in the output.</jc>
+	 * 	restClient.doGet(<jsf>URL</jsf>)
+	 * 		.successPattern(<js>"SUCCESS"</js>)
+	 * 		.run();
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param successPattern A regular expression to look for in the response output.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall successPattern(String successPattern) {
+		addResponsePattern(
+			new ResponsePattern(successPattern) {
+				@Override
+				public void onNoMatch(RestCall rc) throws RestCallException {
+					throw new RestCallException("Success pattern not detected.");
+				}
+			}
+		);
+		return this;
+	}
+
+	/**
+	 * Adds a response pattern finder to look for regular expression matches in the response output.
+	 * <p>
+	 * This method can be called multiple times to add multiple response pattern finders.
+	 * <p>
+	 * {@link ResponsePattern ResponsePatterns} use the {@link #getCapturedResponse()} to read the response text and so does not affect the other output
+	 * 	methods such as {@link #getResponseAsString()}.
+	 *
+	 * @param responsePattern The response pattern finder.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall addResponsePattern(final ResponsePattern responsePattern) {
+		captureResponse();
+		addInterceptor(
+			new RestCallInterceptor() {
+				@Override
+				public void onClose(RestCall restCall) throws RestCallException {
+					responsePattern.match(RestCall.this);
+				}
+			}
+		);
+		return this;
+	}
+
+	/**
+	 * Set configuration settings on this request.
+	 * <p>
+	 * Use {@link RequestConfig#custom()} to create configuration parameters for the request.
+	 *
+	 * @param config The new configuration settings for this request.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall setConfig(RequestConfig config) {
+		this.request.setConfig(config);
+		return this;
+	}
+
+	/**
+	 * @return The HTTP response code.
+	 * @throws RestCallException
+	 * @deprecated Use {@link #run()}.
+	 */
+	@Deprecated
+	public int execute() throws RestCallException {
+		return run();
+	}
+
+	/**
+	 * Method used to execute an HTTP response where you're only interested in the HTTP response code.
+	 * <p>
+	 * The response entity is discarded unless one of the pipe methods have been specified to pipe the
+	 * 	 output to an output stream or writer.
+	 *
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	<jk>try</jk> {
+	 * 		RestClient client = <jk>new</jk> RestClient();
+	 * 		<jk>int</jk> rc = client.doGet(url).execute();
+	 * 		<jc>// Succeeded!</jc>
+	 * 	} <jk>catch</jk> (RestCallException e) {
+	 * 		<jc>// Failed!</jc>
+	 * 	}
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @return This object (for method chaining).
+	 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
+	 */
+	public int run() throws RestCallException {
+		connect();
+		try {
+			StatusLine status = response.getStatusLine();
+			int sc = status.getStatusCode();
+			if (sc >= 400 && ! ignoreErrors)
+				throw new RestCallException(sc, status.getReasonPhrase(), request.getMethod(), request.getURI(), getResponseAsString()).setHttpResponse(response);
+			if (outputStreams.size() > 0 || writers.size() > 0)
+				getReader();
+			return sc;
+		} catch (RestCallException e) {
+			isFailed = true;
+			throw e;
+		} catch (IOException e) {
+			isFailed = true;
+			throw new RestCallException(e).setHttpResponse(response);
+		} finally {
+			close();
+		}
+	}
+
+	/**
+	 * Connects to the REST resource.
+	 * <p>
+	 * 	If this is a <code>PUT</code> or <code>POST</code>, also sends the input to the remote resource.<br>
+	 * <p>
+	 * 	Typically, you would only call this method if you're not interested in retrieving the body of the HTTP response.
+	 * 	Otherwise, you're better off just calling one of the {@link #getReader()}/{@link #getResponse(Class)}/{@link #pipeTo(Writer)}
+	 * 	methods directly which automatically call this method already.
+	 *
+	 * @return This object (for method chaining).
+	 * @throws RestCallException If an exception or <code>400+</code> HTTP status code occurred during the connection attempt.
+	 */
+	public RestCall connect() throws RestCallException {
+
+		if (isConnected)
+			return this;
+		isConnected = true;
+
+		try {
+			int sc = 0;
+			while (retries > 0) {
+				retries--;
+				Exception ex = null;
+				try {
+			response = client.execute(request);
+				sc = response == null ? -1 : response.getStatusLine().getStatusCode();
+				} catch (Exception e) {
+					ex = e;
+					sc = -1;
+				}
+				if (! retryOn.onCode(sc))
+					retries = 0;
+				if (retries > 0) {
+					for (RestCallInterceptor rci : interceptors)
+						rci.onRetry(this, sc, request, response, ex);
+					request.reset();
+					long w = retryInterval;
+					synchronized(this) {
+						wait(w);
+					}
+				} else if (ex != null) {
+					throw ex;
+				}
+			}
+			for (RestCallInterceptor rci : interceptors)
+				rci.onConnect(this, sc, request, response);
+			if (response == null)
+				throw new RestCallException("HttpClient returned a null response");
+			StatusLine sl = response.getStatusLine();
+			String method = request.getMethod();
+			sc = sl.getStatusCode(); // Read it again in case it was changed by one of the interceptors.
+			if (sc >= 400 && ! ignoreErrors)
+				throw new RestCallException(sc, sl.getReasonPhrase(), method, request.getURI(), getResponseAsString()).setHttpResponse(response);
+			if ((sc == 307 || sc == 302) && allowRedirectsOnPosts && method.equalsIgnoreCase("POST")) {
+				if (redirectOnPostsTries-- < 1)
+					throw new RestCallException(sc, "Maximum number of redirects occurred.  Location header: " + response.getFirstHeader("Location"), method, request.getURI(), getResponseAsString());
+				Header h = response.getFirstHeader("Location");
+				if (h != null) {
+					reset();
+					request.setURI(URI.create(h.getValue()));
+					retries++;  // Redirects should affect retries.
+					connect();
+				}
+			}
+
+		} catch (RestCallException e) {
+			isFailed = true;
+			try {
+			close();
+			} catch (RestCallException e2) { /* Ignore */ }
+			throw e;
+		} catch (Exception e) {
+			isFailed = true;
+			close();
+			throw new RestCallException(e).setHttpResponse(response);
+		}
+
+		return this;
+	}
+
+	private void reset() {
+		if (response != null)
+			EntityUtils.consumeQuietly(response.getEntity());
+		request.reset();
+		isConnected = false;
+		isClosed = false;
+		isFailed = false;
+		if (capturedResponseWriter != null)
+			capturedResponseWriter.getBuffer().setLength(0);
+	}
+
+	/**
+	 * Connects to the remote resource (if <code>connect()</code> hasn't already been called) and returns the HTTP response message body as a reader.
+	 * <p>
+	 * 	If an {@link Encoder} has been registered with the {@link RestClient}, then the underlying input stream
+	 * 		will be wrapped in the encoded stream (e.g. a <code>GZIPInputStream</code>).
+	 * <p>
+	 * 	If present, automatically handles the <code>charset</code> value in the <code>Content-Type</code> response header.
+	 * <p>
+	 * 	<b>IMPORTANT:</b>  It is your responsibility to close this reader once you have finished with it.
+	 *
+	 * @return The HTTP response message body reader.  <jk>null</jk> if response was successful but didn't contain a body (e.g. HTTP 204).
+	 * @throws IOException If an exception occurred while streaming was already occurring.
+	 */
+	public Reader getReader() throws IOException {
+		InputStream is = getInputStream();
+		if (is == null)
+			return null;
+
+		// Figure out what the charset of the response is.
+		String cs = null;
+		Header contentType = response.getLastHeader("Content-Type");
+		String ct = contentType == null ? null : contentType.getValue();
+
+		// First look for "charset=" in Content-Type header of response.
+		if (ct != null && ct.contains("charset="))
+			cs = ct.substring(ct.indexOf("charset=")+8).trim();
+
+		if (cs == null)
+			cs = "UTF-8";
+
+		Reader isr = new InputStreamReader(is, cs);
+
+		if (writers.size() > 0) {
+			StringWriter sw = new StringWriter();
+			writers.add(sw, true);
+			IOPipe.create(isr, writers).byLines(byLines).run();
+			return new StringReader(sw.toString());
+		}
+
+		return new InputStreamReader(is, cs);
+	}
+
+	/**
+	 * Returns the response text as a string if {@link #captureResponse()} was called on this object.
+	 * <p>
+	 * Note that while similar to {@link #getResponseAsString()}, this method can be called multiple times
+	 * 	to retrieve the response text multiple times.
+	 * <p>
+	 * Note that this method returns <jk>null</jk> if you have not called one of the methods that cause
+	 * 	the response to be processed.  (e.g. {@link #run()}, {@link #getResponse()}, {@link #getResponseAsString()}.
+	 *
+	 * @return The captured response, or <jk>null</jk> if {@link #captureResponse()} has not been called.
+	 * @throws IllegalStateException If trying to call this method before the response is consumed.
+	 */
+	public String getCapturedResponse() {
+		if (! isClosed)
+			throw new IllegalStateException("This method cannot be called until the response has been consumed.");
+		if (capturedResponse == null && capturedResponseWriter != null && capturedResponseWriter.getBuffer().length() > 0)
+			capturedResponse = capturedResponseWriter.toString();
+		return capturedResponse;
+	}
+
+	/**
+	 * Returns the parser specified on the client to use for parsing HTTP response bodies.
+	 *
+	 * @return The parser.
+	 * @throws RestCallException If no parser was defined on the client.
+	 */
+	protected Parser<?> getParser() throws RestCallException {
+		if (client.parser == null)
+			throw new RestCallException(0, "No parser defined on client", request.getMethod(), request.getURI(), null);
+		return client.parser;
+	}
+
+	/**
+	 * Returns the serializer specified on the client to use for serializing HTTP request bodies.
+	 *
+	 * @return The serializer.
+	 * @throws RestCallException If no serializer was defined on the client.
+	 */
+	protected Serializer<?> getSerializer() throws RestCallException {
+		if (client.serializer == null)
+			throw new RestCallException(0, "No serializer defined on client", request.getMethod(), request.getURI(), null);
+		return client.serializer;
+	}
+
+	/**
+	 * Returns the value of the <code>Content-Length</code> header.
+	 *
+	 * @return The value of the <code>Content-Length</code> header, or <code>-1</code> if header is not present.
+	 * @throws IOException
+	 */
+	public int getContentLength() throws IOException {
+		connect();
+		Header h = response.getLastHeader("Content-Length");
+		if (h == null)
+			return -1;
+		long l = Long.parseLong(h.getValue());
+		if (l > Integer.MAX_VALUE)
+			return Integer.MAX_VALUE;
+		return (int)l;
+	}
+
+	/**
+	 * Connects to the remote resource (if <code>connect()</code> hasn't already been called) and returns the HTTP response message body as an input stream.
+	 * <p>
+	 * 	If an {@link Encoder} has been registered with the {@link RestClient}, then the underlying input stream
+	 * 		will be wrapped in the encoded stream (e.g. a <code>GZIPInputStream</code>).
+	 * <p>
+	 * 	<b>IMPORTANT:</b>  It is your responsibility to close this reader once you have finished with it.
+	 *
+	 * @return The HTTP response message body input stream. <jk>null</jk> if response was successful but didn't contain a body (e.g. HTTP 204).
+	 * @throws IOException If an exception occurred while streaming was already occurring.
+	 * @throws IllegalStateException If an attempt is made to read the response more than once.
+	 */
+	public InputStream getInputStream() throws IOException {
+		if (isClosed)
+			throw new IllegalStateException("Method cannot be called.  Response has already been consumed.");
+		connect();
+		if (response == null)
+			throw new RestCallException("Response was null");
+		if (response.getEntity() == null)  // HTTP 204 results in no content.
+			return null;
+		InputStream is = response.getEntity().getContent();
+
+		if (outputStreams.size() > 0) {
+			ByteArrayInOutStream baios = new ByteArrayInOutStream();
+			outputStreams.add(baios, true);
+			IOPipe.create(is, baios).run();
+			return baios.getInputStream();
+		}
+		return is;
+	}
+
+	/**
+	 * Connects to the remote resource (if {@code connect()} hasn't already been called) and returns the HTTP response message body as plain text.
+	 *
+	 * @return The response as a string.
+	 * @throws RestCallException If an exception or non-200 response code occurred during the connection attempt.
+	 * @throws IOException If an exception occurred while streaming was already occurring.
+	 */
+	public String getResponseAsString() throws IOException {
+		try {
+			Reader r = getReader();
+			String s = IOUtils.read(r).toString();
+			return s;
+		} catch (IOException e) {
+			isFailed = true;
+			throw e;
+		} finally {
+			close();
+		}
+	}
+
+	/**
+	 * Converts the output from the connection into an object of the specified class using the registered {@link Parser}.
+	 *
+	 * @param type The class to convert the input to.
+	 * @param <T> The class to convert the input to.
+	 * @return The parsed output.
+	 * @throws IOException If a connection error occurred.
+	 * @throws ParseException If the input contains a syntax error or is malformed for the <code>Content-Type</code> header.
+	 */
+	public <T> T getResponse(Class<T> type) throws IOException, ParseException {
+		BeanContext bc = getParser().getBeanContext();
+		if (bc == null)
+			bc = BeanContext.DEFAULT;
+		return getResponse(bc.getClassMeta(type));
+	}
+
+	/**
+	 * Parses the output from the connection into the specified type and then wraps that in a {@link PojoRest}.
+	 * <p>
+	 * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
+	 *
+	 * @param innerType The class type of the POJO being wrapped.
+	 * @return The parsed output wapped in a {@link PojoRest}.
+	 * @throws IOException If a connection error occurred.
+	 * @throws ParseException If the input contains a syntax error or is malformed for the <code>Content-Type</code> header.
+	 */
+	public PojoRest getResponsePojoRest(Class<?> innerType) throws IOException, ParseException {
+		return new PojoRest(getResponse(innerType));
+	}
+
+	/**
+	 * Converts the output from the connection into an {@link ObjectMap} and then wraps that in a {@link PojoRest}.
+	 * <p>
+	 * Useful if you want to quickly retrieve a single value from inside of a larger JSON document.
+	 *
+	 * @return The parsed output wapped in a {@link PojoRest}.
+	 * @throws IOException If a connection error occurred.
+	 * @throws ParseException If the input contains a syntax error or is malformed for the <code>Content-Type</code> header.
+	 */
+	public PojoRest getResponsePojoRest() throws IOException, ParseException {
+		return getResponsePojoRest(ObjectMap.class);
+	}
+
+	/**
+	 * Convenience method when you want to parse into a Map&lt;K,V&gt; object.
+	 * 
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	Map&lt;String,MyBean&gt; m = client.doGet(url).getResponseMap(LinkedHashMap.<jk>class</jk>, String.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * </p>
+	 * 		<p>
+	 * A simpler approach is often to just extend the map class you want and just use the normal {@link #getResponse(Class)} method:
+	 * 		</p>
+	 * <p class='bcode'>
+	 * 	<jk>public static class</jk> MyMap <jk>extends</jk> LinkedHashMap&lt;String,MyBean&gt; {}
+	 *
+	 * 	Map&lt;String,MyBean&gt; m = client.doGet(url).getResponse(MyMap.<jk>class</jk>);
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param mapClass The map class to use (e.g. <code>TreeMap</code>)
+	 * @param keyClass The class type of the keys (e.g. <code>String</code>)
+	 * @param valueClass The class type of the values (e.g. <code>MyBean</code>)
+	 * @return The response parsed as a map.
+	 * @throws ParseException
+	 * @throws IOException
+	 */
+	public final <K,V,T extends Map<K,V>> T getResponseMap(Class<T> mapClass, Class<K> keyClass, Class<V> valueClass) throws ParseException, IOException {
+		ClassMeta<T> cm = getBeanContext().getMapClassMeta(mapClass, keyClass, valueClass);
+		return getResponse(cm);
+	}
+
+	/**
+	 * Convenience method when you want to parse into a Collection&lt;E&gt; object.
+	 * 
+	 * <dl>
+	 * 	<dt>Example:</dt>
+	 * 	<dd>
+	 * <p class='bcode'>
+	 * 	List&lt;MyBean&gt; l = client.doGet(url).getResponseCollection(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * </p>
+	 * 		<p>
+	 * 			A simpler approach is often to just extend the collection class you want and just use the normal {@link #getResponse(Class)} method:
+	 * </p>
+	 * <p class='bcode'>
+	 * 	<jk>public static class</jk> MyList <jk>extends</jk> LinkedList&lt;MyBean&gt; {}
+	 *
+	 * 	List&lt;MyBean&gt; l = client.doGet(url).getResponse(MyList.<jk>class</jk>);
+	 * </p>
+	 * 	</dd>
+	 * </dl>
+	 *
+	 * @param collectionClass The collection class to use (e.g. <code>LinkedList</code>)
+	 * @param entryClass The class type of the values (e.g. <code>MyBean</code>)
+	 * @return The response parsed as a collection.
+	 * @throws ParseException
+	 * @throws IOException
+	 */
+	public final <E,T extends Collection<E>> T getResponseCollection(Class<T> collectionClass, Class<E> entryClass) throws ParseException, IOException {
+		ClassMeta<T> cm = getBeanContext().getCollectionClassMeta(collectionClass, entryClass);
+		return getResponse(cm);
+	}
+
+	<T> T getResponse(ClassMeta<T> type) throws IOException, ParseException {
+		try {
+		Parser<?> p = getParser();
+		T o = null;
+		int contentLength = getContentLength();
+			if (! p.isReaderParser()) {
+			InputStream is = getInputStream();
+			o = ((InputStreamParser)p).parse(is, contentLength, type);
+		} else {
+			Reader r = getReader();
+			o = ((ReaderParser)p).parse(r, contentLength, type);
+			}
+		return o;
+		} catch (ParseException e) {
+			isFailed = true;
+			throw e;
+		} catch (IOException e) {
+			isFailed = true;
+			throw e;
+		} finally {
+			close();
+		}
+	}
+
+	BeanContext getBeanContext() throws RestCallException {
+		BeanContext bc = getParser().getBeanContext();
+		if (bc == null)
+			bc = BeanContext.DEFAULT;
+		return bc;
+	}
+
+	/**
+	 * Returns access to the {@link HttpUriRequest} passed to {@link HttpClient#execute(HttpUriRequest)}.
+	 *
+	 * @return The {@link HttpUriRequest} object.
+	 */
+	public HttpUriRequest getRequest() {
+		return request;
+	}
+
+	/**
+	 * Returns access to the {@link HttpResponse} returned by {@link HttpClient#execute(HttpUriRequest)}.
+	 * Returns <jk>null</jk> if {@link #connect()} has not yet been called.
+	 *
+	 * @return The HTTP response object.
+	 * @throws IOException
+	 */
+	public HttpResponse getResponse() throws IOException {
+		connect();
+		return response;
+	}
+
+	/**
+	 * Shortcut for calling <code>getRequest().setHeader(header)</code>
+	 *
+	 * @param header The header to set on the request.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall setHeader(Header header) {
+		request.setHeader(header);
+		return this;
+	}
+
+	/** Use close() */
+	@Deprecated
+	public void consumeResponse() {
+		if (response != null)
+			EntityUtils.consumeQuietly(response.getEntity());
+	}
+
+	/**
+	 * Cleans up this HTTP call.
+	 *
+	 * @return This object (for method chaining).
+	 * @throws RestCallException Can be thrown by one of the {@link RestCallInterceptor#onClose(RestCall)} calls.
+	 */
+	public RestCall close() throws RestCallException {
+		if (response != null)
+			EntityUtils.consumeQuietly(response.getEntity());
+		isClosed = true;
+		if (! isFailed)
+			for (RestCallInterceptor r : interceptors)
+				r.onClose(this);
+		return this;
+	}
+
+	/**
+	 * Adds a {@link RestCallLogger} to the list of interceptors on this class.
+	 *
+	 * @param level The log level to log events at.
+	 * @param log The logger.
+	 * @return This object (for method chaining).
+	 */
+	public RestCall logTo(Level level, Logger log) {
+		addInterceptor(new RestCallLogger(level, log));
+		return this;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCallException.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCallException.class b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCallException.class
new file mode 100755
index 0000000..57f3148
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/client/com/ibm/juno/client/RestCallException.class differ