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 2017/09/08 23:25:37 UTC

svn commit: r21540 [22/27] - in /release/incubator/juneau: juneau-rest-client/ juneau-rest-client/.settings/ juneau-rest-client/bin/ juneau-rest-client/src/ juneau-rest-client/src/main/ juneau-rest-client/src/main/java/ juneau-rest-client/src/main/java...

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,65 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.vars;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.widget.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * HTML widget variable resolver.
+ *
+ * <p>
+ * The format for this var is <js>"$W{widgetName}"</js>.
+ *
+ * <p>
+ * Widgets are simple class that produce some sort of string based on a passed-in HTTP request.
+ *
+ * <p>
+ * They're registered via the following mechanisms:
+ * <ul>
+ * 	<li>{@link HtmlDoc#widgets() @HtmlDoc.widgets()}
+ * 	<li>{@link RestConfig#addHtmlWidget(Class)}
+ * </ul>
+ *
+ * @see org.apache.juneau.svl
+ */
+public class WidgetVar extends SimpleVar {
+
+	/**
+	 * The name of the session or context object that identifies the {@link RestRequest} object.
+	 */
+	private static final String SESSION_req = "req";
+
+	/**
+	 * The name of this variable.
+	 */
+	public static final String NAME = "W";
+
+	/**
+	 * Constructor.
+	 */
+	public WidgetVar() {
+		super(NAME);
+	}
+
+	@Override /* Parameter */
+	public String resolve(VarResolverSession session, String key) throws Exception {
+		RestRequest req = session.getSessionObject(RestRequest.class, SESSION_req);
+		Widget w = req.getWidgets().get(key);
+		if (w == null)
+			return "unknown-widget-"+key;
+		return w.getHtml(req);
+	}
+}
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/package.html
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/package.html (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/package.html Fri Sep  8 23:25:34 2017
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<!--
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ ***************************************************************************************************************************/
+ -->
+<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>Predefined SVL variables</p>
+</body>
+</html>
\ No newline at end of file

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/vars/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,77 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import static org.apache.juneau.dto.html5.HtmlBuilder.*;
+
+import java.net.*;
+import java.util.*;
+
+import org.apache.juneau.dto.html5.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Widget that returns back a list of hyperlinks for rendering the contents of a page in a variety of content types.
+ *
+ * <p>
+ * The variable it resolves is <js>"$W{ContentTypeMenuItem}"</js>.
+ *
+ * <p>
+ * An example of this widget can be found in the <code>PetStoreResource</code> in the examples that provides
+ * a drop-down menu item for rendering all other supported content types in plain text:
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(
+ * 		name=<js>"GET"</js>,
+ * 		path=<js>"/"</js>,
+ * 		widgets={
+ * 			ContentTypeMenuItem.<jk>class</jk>,
+ * 		},
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			links={
+ * 				<js>"up: ..."</js>,
+ * 				<js>"options: ..."</js>,
+ * 				<js>"$W{QueryMenuItem}"</js>,
+ * 				<js>"$W{ContentTypeMenuItem}"</js>,
+ * 				<js>"$W{StyleMenuItem}"</js>,
+ * 				<js>"source: ..."</js>
+ * 			}
+ * 		)
+ * 	)
+ * 	<jk>public</jk> Collection&lt;Pet&gt; getPets() {
+ * </p>
+ *
+ * <p>
+ * It renders the following popup-box:
+ * <br><img class='bordered' src='doc-files/ContentTypeMenuItem.png'>
+ */
+public class ContentTypeMenuItem extends MenuItemWidget {
+
+	@Override /* MenuItemWidget */
+	public String getLabel(RestRequest req) {
+		return "content-type";
+	}
+
+	@Override /* MenuItemWidget */
+	public Div getContent(RestRequest req) {
+		Div div = div();
+		List<MediaType> l = new ArrayList<MediaType>(req.getSerializerGroup().getSupportedMediaTypes());
+		Collections.sort(l);
+		for (MediaType mt : l) {
+			URI uri = req.getUri(true, new AMap<String,String>().append("plainText","true").append("Accept",mt.toString()));
+			div.children(a(uri, mt), br());
+		}
+		return div;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/ContentTypeMenuItem.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,131 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import java.io.*;
+
+import org.apache.juneau.html.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.serializer.*;
+
+/**
+ * A subclass of widgets for rendering menu items with drop-down windows.
+ *
+ * <p>
+ * Defines some simple CSS and Javascript for enabling drop-down menus in the nav section of the page (although
+ * nothing keeps you from using it in an arbitrary location in the page).
+ *
+ * <p>
+ * The script specifies a <js>"menuClick(element)"</js> function that toggles the visibility of the next sibling of the
+ * element.
+ *
+ * <p>
+ * Subclasses should implement the following two methods:
+ * <ul>
+ * 	<li>{@link #getLabel(RestRequest)} - The menu item label.
+ * 	<li>{@link #getContent(RestRequest)} - The menu item content.
+ *
+ * <p>
+ * For example, to render a link that brings up a simple dialog in a div tag:
+ * <p class='bcode'>
+ * 	<ja>@Override</ja>
+ * 	<jk>public</jk> String getLabel() {
+ * 		<jk>return</jk> <js>"my-menu-item"</js>;
+ * 	};
+ *
+ * 	<ja>@Override</ja>
+ * 	<jk>public</jk> Div getLabel() {
+ * 		<jk>return</jk> Html5Builder.<jsm>div</jsm>(<js>"Surprise!"</js>).style(<js>"color:red"</js>);
+ * 	};
+ * </p>
+ *
+ * <p>
+ * The HTML content returned by the {@link #getHtml(RestRequest)} method is added where the <js>"$W{...}"</js> is
+ * referenced in the page.
+ */
+public abstract class MenuItemWidget extends Widget {
+
+	/**
+	 * Returns the Javascript needed for the show and hide actions of the menu item.
+	 */
+	@Override /* Widget */
+	public String getScript(RestRequest req) throws Exception {
+		return loadScript("MenuItemWidget.js");
+	}
+
+	/**
+	 * Defines a <js>"menu-item"</js> class that needs to be used on the outer element of the HTML returned by the
+	 * {@link #getHtml(RestRequest)} method.
+	 */
+	@Override /* Widget */
+	public String getStyle(RestRequest req) throws Exception {
+		return loadStyle("MenuItemWidget.css");
+	}
+
+	@Override /* Widget */
+	public String getHtml(RestRequest req) throws Exception {
+		StringBuilder sb = new StringBuilder();
+		sb.append(""
+			+ "<div class='menu-item'>"
+			+ "\n\t<a class='link' onclick='menuClick(this)'>"+getLabel(req)+"</a>"
+			+ "\n\t<div class='popup-content'>\n"
+		);
+		Object o = getContent(req);
+		if (o instanceof Reader)
+			IOUtils.pipe((Reader)o, new StringBuilderWriter(sb));
+		else if (o instanceof CharSequence)
+			sb.append((CharSequence)o);
+		else {
+			SerializerSessionArgs args = new SerializerSessionArgs(req.getProperties(), null, req.getLocale(), null, null, req.getUriContext());
+			WriterSerializerSession session = HtmlSerializer.DEFAULT.createSession(args);
+			try {
+				session.indent = 2;
+				session.serialize(sb, o);
+			} finally {
+				session.close();
+			}
+		}
+		sb.append(""
+			+ "\n\t</div>"
+			+ "\n</div>"
+		);
+		return sb.toString();
+	}
+
+	/**
+	 * The label for the menu item as it's rendered in the menu bar.
+	 *
+	 * @param req The HTTP request object.
+	 * @return The menu item label.
+	 * @throws Exception
+	 */
+	public abstract String getLabel(RestRequest req) throws Exception;
+
+	/**
+	 * The content of the popup.
+	 *
+	 * @param req The HTTP request object.
+	 * @return
+	 * 	The content of the popup.
+	 * 	<br>Can be any of the following types:
+	 * 	<ul>
+	 * 		<li>{@link Reader} - Serialized directly to the output.
+	 * 		<li>{@link CharSequence} - Serialized directly to the output.
+	 * 		<li>Other - Serialized as HTML using {@link HtmlSerializer#DEFAULT}.
+	 * 			<br>Note that this includes any of the {@link org.apache.juneau.dto.html5} beans.
+	 * 	</ul>
+	 * @throws Exception
+	 */
+	public abstract Object getContent(RestRequest req) throws Exception;
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,57 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.*;
+
+/**
+ * Widget that places a powered-by-Apache message on the page.
+ *
+ * <p>
+ * The variable it resolves is <js>"$W{PoweredByApache}"</js>.
+ *
+ * <p>
+ * It produces a simple Apache icon floating on the right.
+ * Typically it's used in the footer of the page, as shown below in the <code>RootResources</code> from the examples:
+ *
+ * <p class='bcode'>
+ * 	<ja>@RestResource</ja>(
+ * 		path=<js>"/"</js>,
+ * 		title=<js>"Root resources"</js>,
+ * 		description=<js>"Example of a router resource page."</js>,
+ * 		widgets={
+ * 			PoweredByApache.<jk>class</jk>
+ * 		},
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			footer=<js>"$W{PoweredByApache}"</js>
+ * 		)
+ * </p>
+ *
+ * <p>
+ * It renders the following image:
+ * <img class='bordered' src='doc-files/PoweredByApacheWidget.png'>
+ */
+public class PoweredByApache extends Widget {
+
+	/**
+	 * Returns an Apache image tag hyperlinked to <js>"http://apache.org"</js>
+	 */
+	@Override /* Widget */
+	public String getHtml(RestRequest req) throws Exception {
+		UriResolver r = req.getUriResolver();
+		return "<a href='http://apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/asf.png")+"'>";
+	}
+}
+
+

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByApache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,56 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.*;
+
+/**
+ * Widget that places a powered-by-Juneau message on the page.
+ *
+ * <p>
+ * The variable it resolves is <js>"$W{PoweredByJuneau}"</js>.
+ *
+ * <p>
+ * It produces a simple Apache Juneau icon floating on the right.
+ * Typically it's used in the footer of the page, as shown below in the <code>AddressBookResource</code> from the examples:
+ *
+ * <p class='bcode'>
+ * 	<ja>@RestResource</ja>(
+ * 		path=<js>"/addressBook"</js>,
+ * 		widgets={
+ * 			PoweredByJuneau.<jk>class</jk>
+ * 		},
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			footer=<js>"$W{PoweredByJuneau}"</js>
+ * 		)
+ * </p>
+ *
+ * <p>
+ * It renders the following image:
+ * <img class='bordered' src='doc-files/PoweredByJuneauWidget.png'>
+ */
+public class PoweredByJuneau extends Widget {
+
+
+	/**
+	 * Returns an Apache Juneau image tag hyperlinked to <js>"http://juneau.apache.org"</js>
+	 */
+	@Override /* Widget */
+	public String getHtml(RestRequest req) throws Exception {
+		UriResolver r = req.getUriResolver();
+		return "<a href='http://juneau.apache.org'><img style='float:right;padding-right:20px;height:32px' src='"+r.resolve("servlet:/htdocs/juneau.png")+"'>";
+	}
+}
+
+

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/PoweredByJuneau.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,88 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.converters.*;
+
+/**
+ * Widget that returns a menu-item drop-down form for entering search/view/sort arguments.
+ *
+ * <p>
+ * The variable it resolves is <js>"$W{QueryMenuItem}"</js>.
+ *
+ * <p>
+ * This widget is designed to be used in conjunction with the {@link Queryable} converter, although implementations
+ * can process the query parameters themselves if they wish to do so by using the {@link RequestQuery#getSearchArgs()}
+ * method to retrieve the arguments and process the data themselves.
+ *
+ * <p>
+ * An example of this widget can be found in the <code>PetStoreResource</code> in the examples that provides
+ * search/view/sort capabilities against the collection of POJOs:
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(
+ * 		name=<js>"GET"</js>,
+ * 		path=<js>"/"</js>,
+ * 		widgets={
+ * 			QueryMenuItem.<jk>class</jk>,
+ * 		},
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			links={
+ * 				<js>"up: ..."</js>,
+ * 				<js>"options: ..."</js>,
+ * 				<js>"$W{QueryMenuItem}"</js>,
+ * 				<js>"$W{ContentTypeMenuItem}"</js>,
+ * 				<js>"$W{StyleMenuItem}"</js>,
+ * 				<js>"source: ..."</js>
+ * 			}
+ * 		),
+ * 		converters=Queryable.<jk>class</jk>
+ * 	)
+ * 	<jk>public</jk> Collection&lt;Pet&gt; getPets() {
+ * </p>
+ *
+ * <p>
+ * It renders the following popup-box:
+ * <br><img class='bordered' src='doc-files/QueryMenuItem_1.png'>
+ *
+ * <p>
+ * Tooltips are provided by hovering over the field names.
+ * <br><img class='bordered' src='doc-files/QueryMenuItem_2.png'>
+ *
+ * <p>
+ * When submitted, the form submits a GET request against the current URI with special GET search API query parameters.
+ * <br>(e.g. <js>"?s=column1=Foo*&amp;v=column1,column2&amp;o=column1,column2-&amp;p=100&amp;l=100"</js>).
+ * <br>The {@link Queryable} class knows how to perform these filters against collections of POJOs.
+ */
+public class QueryMenuItem extends MenuItemWidget {
+
+	/**
+	 * Returns CSS for the tooltips.
+	 */
+	@Override
+	public String getStyle(RestRequest req) throws Exception {
+		return super.getStyle(req)
+			+ "\n"
+			+ loadStyle("QueryMenuItem.css");
+	}
+
+	@Override /* MenuItemWidget */
+	public String getLabel(RestRequest req) throws Exception {
+		return "query";
+	}
+
+	@Override /* MenuItemWidget */
+	public String getContent(RestRequest req) throws Exception {
+		return loadHtml("QueryMenuItem.html");
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/QueryMenuItem.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/StyleMenuItem.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/StyleMenuItem.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/StyleMenuItem.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,72 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import static org.apache.juneau.dto.html5.HtmlBuilder.*;
+
+import org.apache.juneau.dto.html5.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Widget that returns back a list of hyperlinks for rendering the contents of a page in the various default styles.
+ *
+ * <p>
+ * The variable it resolves is <js>"$W{StyleMenuItem}"</js>.
+ *
+ * <p>
+ * An example of this widget can be found in the <code>PetStoreResource</code> in the examples that provides
+ * a drop-down menu item for rendering all other supported content types in plain text:
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(
+ * 		name=<js>"GET"</js>,
+ * 		path=<js>"/"</js>,
+ * 		widgets={
+ * 			StyleMenuItem.<jk>class</jk>,
+ * 		},
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			links={
+ * 				<js>"up: ..."</js>,
+ * 				<js>"options: ..."</js>,
+ * 				<js>"$W{QueryMenuItem}"</js>,
+ * 				<js>"$W{ContentTypeMenuItem}"</js>,
+ * 				<js>"$W{StyleMenuItem}"</js>,
+ * 				<js>"source: ..."</js>
+ * 			}
+ * 		)
+ * 	)
+ * 	<jk>public</jk> Collection&lt;Pet&gt; getPets() {
+ * </p>
+ */
+public class StyleMenuItem extends MenuItemWidget {
+
+	private static final String[] BUILT_IN_STYLES = {"devops", "light", "original", "dark"};
+
+	@Override /* MenuItemWidget */
+	public String getLabel(RestRequest req) {
+		return "styles";
+	}
+	/**
+	 * Looks at the supported media types from the request and constructs a list of hyperlinks to render the data
+	 * as plain-text.
+	 */
+	@Override /* Widget */
+	public Div getContent(RestRequest req) throws Exception {
+		Div div = div();
+		for (String s : BUILT_IN_STYLES) {
+			java.net.URI uri = req.getUri(true, new AMap<String,String>().append("stylesheet", "styles/"+s+".css"));
+			div.children(a(uri, s), br());
+		}
+		return div;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/StyleMenuItem.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Tooltip.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Tooltip.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Tooltip.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,97 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import static org.apache.juneau.dto.html5.HtmlBuilder.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.dto.html5.*;
+
+/**
+ * Simple template for adding tooltips to HTML5 bean constructs, typically in menu item widgets.
+ *
+ * <p>
+ * Tooltips depend on the existence of the <code>tooltip</code> and <code>tooltiptext</code> styles that should be
+ * present in the stylesheet for the document.
+ *
+ * <p>
+ * The following examples shows how tooltips can be added to a menu item widget.
+ *
+ * <p class='bcode'>
+ * <jk>public class</jk> MyFormMenuItem <jk>extends</jk> MenuItemWidget {
+ *
+ * 	<ja>@Override</ja>
+ * 	<jk>public</jk> String getLabel(RestRequest req) <jk>throws</jk> Exception {
+ * 		<jk>return</jk> <js>"myform"</js>;
+ * 	}
+ *
+ * 	<ja>@Override</ja>
+ * 	<jk>public</jk> Object getContent(RestRequest req) <jk>throws</jk> Exception {
+ * 		<jk>return</jk> div(
+ * 			<jsm>form</jsm>().id(<js>"form"</js>).action(<js>"servlet:/form"</js>).method(<js>"POST"</js>).children(
+ * 				<jsm>table</jsm>(
+ * 					<jsm>tr</jsm>(
+ * 						<jsm>th</jsm>(<js>"Field 1:"</js>),
+ * 						<jsm>td</jsm>(<jsm>input</jsm>().name(<js>"field1"</js>).type(<js>"text"</js>)),
+ * 						<jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"This is field #1!"</js>, br(), <js>"(e.g. '"</js>, code(<js>"Foo"</js>), <js>"')"</js>))
+ * 					),
+ * 					<jsm>tr</jsm>(
+ * 						<jsm>th</jsm>(<js>"Field 2:"</js>),
+ * 						<jsm>td</jsm>(<jsm>input</jsm>().name(<js>"field2"</js>).type(<js>"text"</js>)),
+ * 						<jsm>td</jsm>(<jk>new</jk> Tooltip(<js>"(?)"</js>, <js>"This is field #2!"</js>, br(), <js>"(e.g. '"</js>, code(<js>"Bar"</js>), <js>"')"</js>))
+ * 					)
+ * 				)
+ * 			)
+ * 		);
+ * 	}
+ * }
+ * </p>
+ */
+public class Tooltip {
+
+	private final String display;
+	private final List<Object> content;
+
+   /**
+    * Constructor.
+    *
+    * @param display
+    * 	The normal display text.
+    * 	This is what gets rendered normally.
+    * @param content
+    * 	The hover contents.
+    * 	Typically a list of strings, but can also include any HTML5 beans as well.
+    */
+   public Tooltip(String display, Object...content) {
+   	this.display = display;
+   	this.content = new ArrayList<Object>(Arrays.asList(content));
+   }
+
+   /**
+    * The swap method.
+    *
+    * <p>
+    * Converts this bean into a div tag with contents.
+    *
+    * @param session The bean session.
+    * @return The swapped contents of this bean.
+    */
+   public Div swap(BeanSession session) {
+      return div(
+      	small(display),
+      	span()._class("tooltiptext").children(content)
+      )._class("tooltip");
+   }
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Tooltip.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java
==============================================================================
--- release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java (added)
+++ release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java Fri Sep  8 23:25:34 2017
@@ -0,0 +1,273 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest.widget;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.utils.*;
+
+/**
+ * Defines an interface for resolvers of <js>"$W{...}"</js> string variables.
+ *
+ * <p>
+ * Widgets are associated with resources through the following
+ * <ul>
+ * 	<li>{@link HtmlDoc#widgets() @HtmlDoc.widgets}
+ * 	<li>{@link RestConfig#addHtmlWidget(Class)}
+ * </ul>
+ *
+ * <p>
+ * Widgets allow you to add arbitrary HTML, CSS, and Javascript to the page.
+ *
+ * <p>
+ * The HTML content returned by the {@link #getHtml(RestRequest)} method is added where the <js>"$W{...}"</js> is
+ * referenced in the page.
+ * The Javascript and stylesheet content is added to the header of the page.
+ * They allow you to control the look and behavior of your widgets.
+ *
+ * <p>
+ * The following examples shows how to associate a widget with a REST method and then have it rendered in the links
+ * and aside section of the page:
+ *
+ * <p class='bcode'>
+ * 	<ja>@RestMethod</ja>(
+ * 		widgets={
+ * 			MyWidget.<jk>class</jk>
+ * 		}
+ * 		htmldoc=<ja>@HtmlDoc</ja>(
+ * 			links={
+ * 				<js>"$W{MyWidget}"</js>
+ * 			},
+ * 			aside={
+ * 				<js>"Check out this widget:  $W{MyWidget}"</js>
+ * 			}
+ * 		)
+ * 	)
+ * </p>
+ *
+ * <p>
+ * The following shows an example of a widget that renders an image located in the <code>htdocs</code> static files
+ * directory in your classpath (see {@link RestResource#staticFiles()}):
+ * <p class='bcode'>
+ * 	<jk>public class</jk> MyWidget <jk>extends</jk> Widget {
+ *
+ * 		<ja>@Override</ja>
+ * 		<jk>public</jk> String getHtml(RestRequest req) <jk>throws</jk> Exception {
+ * 			UriResolver r = req.getUriResolver();
+ * 			<jk>return</jk> <js>"&lt;img class='myimage' onclick='myalert(this)' src='"</js>+r.resolve(<js>"servlet:/htdocs/myimage.png"</js>)+<js>"'&gt;"</js>;
+ * 		}
+ *
+ * 		<ja>@Override</ja>
+ * 		<jk>public</jk> String getScript(RestRequest req) <jk>throws</jk> Exception {
+ * 			<jk>return</jk> <js>""</js>
+ * 				+ <js>"\n function myalert(imageElement) {"</js>
+ * 				+ <js>"\n 	alert('cool!');"</js>
+ * 				+ <js>"\n }"</js>;
+ * 		}
+ *
+ * 		<ja>@Override</ja>
+ * 		<jk>public</jk> String getStyle(RestRequest req) <jk>throws</jk> Exception {
+ * 			<jk>return</jk> <js>""</js>
+ * 				+ <js>"\n .myimage {"</js>
+ * 				+ <js>"\n 	border: 10px solid red;"</js>
+ * 				+ <js>"\n }"</js>;
+ * 		}
+ * 	}
+ * </p>
+ *
+ * <p>
+ * Note the {@link #getResourceAsString(String)} and {@link #getResourceAsString(String, Locale)} convenience methods
+ * provided for quickly loading javascript and css files from the classpath or file system.
+ * These are useful if your script or styles are complex and you want them loaded from files.
+ *
+ * <p>
+ * <p class='bcode'>
+ * 	<jk>public class</jk> MyWidget <jk>extends</jk> Widget {
+ *
+ * 		...
+ *
+ * 		<ja>@Override</ja>
+ * 		<jk>public</jk> String getScript(RestRequest req) <jk>throws</jk> Exception {
+ * 			<jk>return</jk> getResourceAsString(<js>"MyWidget.js"</js>);
+ * 		}
+ *
+ * 		<ja>@Override</ja>
+ * 		<jk>public</jk> String getStyle(RestRequest req) <jk>throws</jk> Exception {
+ * 			<jk>return</jk> getResourceAsString(<js>"MyWidget.css"</js>);
+ * 		}
+ * 	}
+ * </p>
+ */
+public abstract class Widget {
+
+	private final ResourceFinder resourceFinder = new ResourceFinder(getClass());
+
+	/**
+	 * The widget key.
+	 *
+	 * <p>
+	 * (i.e. The variable name inside the <js>"$W{...}"</js> variable).
+	 *
+	 * <p>
+	 * The returned value must not be <jk>null</jk>.
+	 *
+	 * <p>
+	 * If not overridden, the default value is the class simple name.
+	 *
+	 * @return The widget key.
+	 */
+	public String getName() {
+		return getClass().getSimpleName();
+	}
+
+	/**
+	 * Resolves the HTML content for this widget.
+	 *
+	 * <p>
+	 * A returned value of <jk>null</jk> will cause nothing to be added to the page.
+	 *
+	 * @param req The HTTP request object.
+	 * @return The HTML content of this widget.
+	 * @throws Exception
+	 */
+	public String getHtml(RestRequest req) throws Exception {
+		return null;
+	}
+
+	/**
+	 * Resolves any Javascript that should be added to the <xt>&lt;head&gt;/&lt;script&gt;</xt> element.
+	 *
+	 * <p>
+	 * A returned value of <jk>null</jk> will cause nothing to be added to the page.
+	 *
+	 * @param req The HTTP request object.
+	 * @return The Javascript needed by this widget.
+	 * @throws Exception
+	 */
+	public String getScript(RestRequest req) throws Exception {
+		return null;
+	}
+
+	/**
+	 * Resolves any CSS styles that should be added to the <xt>&lt;head&gt;/&lt;style&gt;</xt> element.
+	 *
+	 * <p>
+	 * A returned value of <jk>null</jk> will cause nothing to be added to the page.
+	 *
+	 * @param req The HTTP request object.
+	 * @return The CSS styles needed by this widget.
+	 * @throws Exception
+	 */
+	public String getStyle(RestRequest req) throws Exception {
+		return null;
+	}
+
+	/**
+	 * Retrieves the specified classpath resource and returns the contents as a string.
+	 *
+	 * <p>
+	 * Same as {@link Class#getResourceAsStream(String)} except if it doesn't find the resource on this class, searches
+	 * up the parent hierarchy chain.
+	 *
+	 * <p>
+	 * If the resource cannot be found in the classpath, then an attempt is made to look relative to the JVM working directory.
+	 * <br>Path traversals outside the working directory are not allowed for security reasons.
+	 *
+	 * @param name Name of the desired resource.
+	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
+	 * @throws IOException
+	 */
+	protected String getResourceAsString(String name) throws IOException {
+		return resourceFinder.getResourceAsString(name);
+	}
+
+	/**
+	 * Same as {@link #getResourceAsString(String)} except also looks for localized-versions of the file.
+	 *
+	 * <p>
+	 * If the <code>locale</code> is specified, then we look for resources whose name matches that locale.
+	 * <br>For example, if looking for the resource <js>"MyResource.txt"</js> for the Japanese locale, we will look for
+	 * files in the following order:
+	 * <ol>
+	 * 	<li><js>"MyResource_ja_JP.txt"</js>
+	 * 	<li><js>"MyResource_ja.txt"</js>
+	 * 	<li><js>"MyResource.txt"</js>
+	 * </ol>
+	 *
+	 *
+	 * @param name Name of the desired resource.
+	 * @param locale The locale.  Can be <jk>null</jk>.
+	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
+	 * @throws IOException
+	 */
+	protected String getResourceAsString(String name, Locale locale) throws IOException {
+		return resourceFinder.getResourceAsString(name, locale);
+	}
+
+	/**
+	 * Convenience method for calling {@link #getResourceAsString(String)} except also strips Javascript comments from
+	 * the file.
+	 *
+	 * <p>
+	 * Comments are assumed to be Java-style block comments: <js>"/*"</js>.
+	 *
+	 * @param name Name of the desired resource.
+	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
+	 * @throws IOException
+	 */
+	protected String loadScript(String name) throws IOException {
+		String s = getResourceAsString(name);
+		if (s != null)
+			s = s.replaceAll("(?s)\\/\\*(.*?)\\*\\/\\s*", "");
+		return s;
+	}
+
+	/**
+	 * Convenience method for calling {@link #getResourceAsString(String)} except also strips CSS comments from
+	 * the file.
+	 *
+	 * <p>
+	 * Comments are assumed to be Java-style block comments: <js>"/*"</js>.
+	 *
+	 * @param name Name of the desired resource.
+	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
+	 * @throws IOException
+	 */
+	protected String loadStyle(String name) throws IOException {
+		String s = getResourceAsString(name);
+		if (s != null)
+			s = s.replaceAll("(?s)\\/\\*(.*?)\\*\\/\\s*", "");
+		return s;
+	}
+
+	/**
+	 * Convenience method for calling {@link #getResourceAsString(String)} except also strips HTML comments from the
+	 * file.
+	 *
+	 * <p>
+	 * Comment are assumed to be <js>"<!-- -->"</js> code blocks.
+	 *
+	 * @param name Name of the desired resource.
+	 * @return The resource converted to a string, or <jk>null</jk> if the resource could not be found.
+	 * @throws IOException
+	 */
+	protected String loadHtml(String name) throws IOException {
+		String s = getResourceAsString(name);
+		if (s != null)
+			s = s.replaceAll("(?s)<!--(.*?)-->\\s*", "");
+		return s;
+	}
+}

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/Widget.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/ContentTypeMenuItem.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/ContentTypeMenuItem.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/PoweredByApacheWidget.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/PoweredByApacheWidget.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/PoweredByJuneauWidget.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/PoweredByJuneauWidget.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/QueryMenuItem_1.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/QueryMenuItem_1.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/QueryMenuItem_2.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/doc-files/QueryMenuItem_2.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/resources/org/apache/juneau/rest/htdocs/MethodExampleResource1.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/resources/org/apache/juneau/rest/htdocs/MethodExampleResource1.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: release/incubator/juneau/juneau-rest-server/src/main/resources/org/apache/juneau/rest/htdocs/asf.png
==============================================================================
Binary file - no diff available.

Propchange: release/incubator/juneau/juneau-rest-server/src/main/resources/org/apache/juneau/rest/htdocs/asf.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream