This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new b1d8df4 Swagger UI enhancements.
b1d8df4 is described below
commit b1d8df48176cddbdf7d2a92bf454e0589af92cfa
Author: JamesBognar <[email protected]>
AuthorDate: Sun Apr 15 14:27:11 2018 -0400
Swagger UI enhancements.
---
.../apache/juneau/jena/RdfBeanPropertyMeta.java | 16 +-
.../org/apache/juneau/jena/RdfParserSession.java | 7 +-
.../apache/juneau/jena/RdfSerializerSession.java | 67 ++--
.../apache/juneau/html/HtmlBeanPropertyMeta.java | 33 ++
.../java/org/apache/juneau/html/HtmlClassMeta.java | 18 +
.../apache/juneau/html/HtmlSerializerSession.java | 90 +++--
.../java/org/apache/juneau/html/HtmlWriter.java | 2 +-
.../org/apache/juneau/html/annotation/Html.java | 1 -
.../apache/juneau/html/annotation/HtmlFormat.java | 12 +
.../java/org/apache/juneau/internal/AsciiSet.java | 12 +
.../org/apache/juneau/internal/ObjectUtils.java | 3 +-
.../org/apache/juneau/internal/StringUtils.java | 84 ++++-
.../jsonschema/JsonSchemaBeanPropertyMeta.java | 13 +
.../org/apache/juneau/xml/XmlBeanPropertyMeta.java | 9 +
.../apache/juneau/xml/XmlSerializerSession.java | 44 ++-
.../main/java/org/apache/juneau/xml/XmlUtils.java | 2 +-
.../xmlschema/XmlSchemaSerializerSession.java | 4 +-
juneau-doc/src/main/javadoc/overview.html | 26 +-
juneau-examples/juneau-examples-rest/examples.cfg | 15 +-
.../juneau/examples/rest/JsonSchemaResource.java | 22 +-
.../apache/juneau/examples/rest/RootResources.java | 1 -
.../juneau/examples/rest/SqlQueryResource.java | 34 +-
.../juneau/examples/rest/StaticFilesResource.java | 83 ----
.../juneau/examples/rest/TempDirResource.java | 9 +-
.../examples/rest/UrlEncodedFormResource.java | 13 +-
.../src/main/resources/examples.cfg | 147 --------
.../examples/rest/JsonSchemaResource_example.json | 50 ++-
.../examples/rest/TestMultiPartFormPostsTest.java | 2 +-
.../microservice/resources/ConfigResource.java | 233 ++++++------
.../microservice/resources/DirectoryResource.java | 293 +++++++-------
.../microservice/resources/LogsResource.java | 420 +++++++++++----------
.../my-microservice.cfg | 16 +-
.../apache/juneau/rest/BasicRestInfoProvider.java | 4 +-
33 files changed, 926 insertions(+), 859 deletions(-)
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
index dd1de16..d1054de 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
@@ -12,8 +12,6 @@
//
***************************************************************************************************************************
package org.apache.juneau.jena;
-import static org.apache.juneau.jena.RdfCollectionFormat.*;
-
import java.util.*;
import org.apache.juneau.*;
@@ -26,7 +24,13 @@ import org.apache.juneau.xml.*;
*/
public class RdfBeanPropertyMeta extends BeanPropertyMetaExtended {
- private RdfCollectionFormat collectionFormat = DEFAULT;
+ /**
+ * Default instance.
+ */
+ public static final RdfBeanPropertyMeta DEFAULT = new
RdfBeanPropertyMeta();
+
+
+ private RdfCollectionFormat collectionFormat =
RdfCollectionFormat.DEFAULT;
private Namespace namespace = null;
private boolean isBeanUri;
@@ -42,7 +46,7 @@ public class RdfBeanPropertyMeta extends
BeanPropertyMetaExtended {
List<RdfSchema> schemas = bpm.findAnnotations(RdfSchema.class);
for (Rdf rdf : rdfs) {
- if (collectionFormat == DEFAULT)
+ if (collectionFormat == RdfCollectionFormat.DEFAULT)
collectionFormat = rdf.collectionFormat();
if (rdf.beanUri())
isBeanUri = true;
@@ -50,6 +54,10 @@ public class RdfBeanPropertyMeta extends
BeanPropertyMetaExtended {
namespace = RdfUtils.findNamespace(rdfs, schemas);
}
+
+ private RdfBeanPropertyMeta() {
+ super(null);
+ }
/**
* Returns the RDF collection format of this property from the {@link
Rdf#collectionFormat} annotation on this bean
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
index 3eff76c..5387a91 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
@@ -221,8 +221,11 @@ public class RdfParserSession extends ReaderParserSession {
}
private boolean isMultiValuedCollections(BeanPropertyMeta pMeta) {
- if (pMeta != null &&
pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() !=
RdfCollectionFormat.DEFAULT)
- return
pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() ==
RdfCollectionFormat.MULTI_VALUED;
+ RdfBeanPropertyMeta bpRdf = (pMeta == null ?
RdfBeanPropertyMeta.DEFAULT : pMeta.getExtendedMeta(RdfBeanPropertyMeta.class));
+
+ if (bpRdf.getCollectionFormat() != RdfCollectionFormat.DEFAULT)
+ return bpRdf.getCollectionFormat() ==
RdfCollectionFormat.MULTI_VALUED;
+
return collectionFormat == RdfCollectionFormat.MULTI_VALUED;
}
diff --git
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
index 06ffa7c..4e83b98 100644
---
a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
+++
b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
@@ -261,7 +261,7 @@ public final class RdfSerializerSession extends
WriterSerializerSession {
if (o instanceof BeanMap) {
BeanMap bm = (BeanMap)o;
Object uri = null;
- RdfBeanMeta rbm =
(RdfBeanMeta)bm.getMeta().getExtendedMeta(RdfBeanMeta.class);
+ RdfBeanMeta rbm = bRdf(bm.getMeta());
if (rbm.hasBeanUri())
uri = rbm.getBeanUriProperty().get(bm,
null);
String uri2 = getUri(uri, null);
@@ -276,7 +276,7 @@ public final class RdfSerializerSession extends
WriterSerializerSession {
} else if (sType.isBean()) {
BeanMap bm = toBeanMap(o);
Object uri = null;
- RdfBeanMeta rbm =
(RdfBeanMeta)bm.getMeta().getExtendedMeta(RdfBeanMeta.class);
+ RdfBeanMeta rbm = bRdf(bm.getMeta());
if (rbm.hasBeanUri())
uri = rbm.getBeanUriProperty().get(bm, null);
String uri2 = getUri(uri, null);
@@ -284,13 +284,17 @@ public final class RdfSerializerSession extends
WriterSerializerSession {
serializeBeanMap(bm, (Resource)n, typeName);
} else if (sType.isCollectionOrArray() || (wType != null &&
wType.isCollection())) {
+
Collection c = sort(sType.isCollection() ?
(Collection)o : toList(sType.getInnerClass(), o));
RdfCollectionFormat f = collectionFormat;
- RdfClassMeta rcm =
sType.getExtendedMeta(RdfClassMeta.class);
- if (rcm.getCollectionFormat() !=
RdfCollectionFormat.DEFAULT)
- f = rcm.getCollectionFormat();
- if (bpm != null &&
bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat() !=
RdfCollectionFormat.DEFAULT)
- f =
bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getCollectionFormat();
+ RdfClassMeta cRdf = cRdf(sType);
+ RdfBeanPropertyMeta bpRdf = bpRdf(bpm);
+
+ if (cRdf.getCollectionFormat() !=
RdfCollectionFormat.DEFAULT)
+ f = cRdf.getCollectionFormat();
+ if (bpRdf.getCollectionFormat() !=
RdfCollectionFormat.DEFAULT)
+ f = bpRdf.getCollectionFormat();
+
switch (f) {
case BAG: n = serializeToContainer(c, eType,
m.createBag()); break;
case LIST: n = serializeToList(c, eType); break;
@@ -346,32 +350,34 @@ public final class RdfSerializerSession extends
WriterSerializerSession {
List<BeanPropertyValue> l = m.getValues(isTrimNulls(), typeName
!= null ? createBeanTypeNameProperty(m, typeName) : null);
Collections.reverse(l);
for (BeanPropertyValue bpv : l) {
- BeanPropertyMeta pMeta = bpv.getMeta();
- ClassMeta<?> cMeta = pMeta.getClassMeta();
-
- if
(pMeta.getExtendedMeta(RdfBeanPropertyMeta.class).isBeanUri())
+
+ BeanPropertyMeta bpMeta = bpv.getMeta();
+ ClassMeta<?> cMeta = bpMeta.getClassMeta();
+ RdfBeanPropertyMeta bpRdf = bpRdf(bpMeta);
+ XmlBeanPropertyMeta bpXml = bpXml(bpMeta);
+
+ if (bpRdf.isBeanUri())
continue;
String key = bpv.getName();
Object value = bpv.getValue();
Throwable t = bpv.getThrown();
if (t != null)
- onBeanGetterException(pMeta, t);
+ onBeanGetterException(bpMeta, t);
if (canIgnoreValue(cMeta, key, value))
continue;
- BeanPropertyMeta bpm = bpv.getMeta();
- Namespace ns =
bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getNamespace();
+ Namespace ns = bpRdf.getNamespace();
if (ns == null && useXmlNamespaces)
- ns =
bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+ ns = bpXml.getNamespace();
if (ns == null)
ns = juneauBpNs;
else if (autoDetectNamespaces)
addModelPrefix(ns);
Property p = model.createProperty(ns.getUri(),
encodeElementName(key));
- RDFNode n = serializeAnything(value, pMeta.isUri(),
cMeta, key, pMeta, r);
+ RDFNode n = serializeAnything(value, bpMeta.isUri(),
cMeta, key, bpMeta, r);
if (n != null)
r.addProperty(p, n);
}
@@ -399,14 +405,15 @@ public final class RdfSerializerSession extends
WriterSerializerSession {
private void serializeToMultiProperties(Collection c, ClassMeta<?>
sType,
BeanPropertyMeta bpm, String attrName, Resource
parentResource) throws Exception {
+
ClassMeta<?> elementType = sType.getElementType();
+ RdfBeanPropertyMeta bpRdf = bpRdf(bpm);
+ XmlBeanPropertyMeta bpXml = bpXml(bpm);
+
for (Object e : c) {
- Namespace ns = null;
- if (bpm != null) {
- ns =
bpm.getExtendedMeta(RdfBeanPropertyMeta.class).getNamespace();
- if (ns == null && useXmlNamespaces)
- ns =
bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
- }
+ Namespace ns = bpRdf.getNamespace();
+ if (ns == null && useXmlNamespaces)
+ ns = bpXml.getNamespace();
if (ns == null)
ns = juneauBpNs;
else if (autoDetectNamespaces)
@@ -416,4 +423,20 @@ public final class RdfSerializerSession extends
WriterSerializerSession {
parentResource.addProperty(p, n2);
}
}
+
+ private static RdfClassMeta cRdf(ClassMeta<?> cm) {
+ return cm.getExtendedMeta(RdfClassMeta.class);
+ }
+
+ private static XmlBeanPropertyMeta bpXml(BeanPropertyMeta pMeta) {
+ return pMeta == null ? XmlBeanPropertyMeta.DEFAULT :
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+ }
+
+ private static RdfBeanPropertyMeta bpRdf(BeanPropertyMeta pMeta) {
+ return pMeta == null ? RdfBeanPropertyMeta.DEFAULT :
pMeta.getExtendedMeta(RdfBeanPropertyMeta.class);
+ }
+
+ private static RdfBeanMeta bRdf(BeanMeta bm) {
+ return (RdfBeanMeta)bm.getExtendedMeta(RdfBeanMeta.class);
+ }
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
index 5380ebf..c9758d9 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
@@ -22,6 +22,11 @@ import org.apache.juneau.html.annotation.*;
@SuppressWarnings("rawtypes")
public final class HtmlBeanPropertyMeta extends BeanPropertyMetaExtended {
+ /**
+ * Default instance.
+ */
+ public static final HtmlBeanPropertyMeta DEFAULT = new
HtmlBeanPropertyMeta();
+
private final boolean noTables, noTableHeaders;
private final HtmlFormat format;
private final HtmlRender render;
@@ -51,6 +56,16 @@ public final class HtmlBeanPropertyMeta extends
BeanPropertyMetaExtended {
this.anchorText = b.anchorText;
}
+ private HtmlBeanPropertyMeta() {
+ super(null);
+ this.format = HtmlFormat.HTML;
+ this.noTables = false;
+ this.noTableHeaders = false;
+ this.render = null;
+ this.link = null;
+ this.anchorText = null;
+ }
+
static final class Builder {
boolean noTables, noTableHeaders;
HtmlFormat format = HtmlFormat.HTML;
@@ -111,6 +126,24 @@ public final class HtmlBeanPropertyMeta extends
BeanPropertyMetaExtended {
}
/**
+ * Returns <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_CDC}.
+ *
+ * @return <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_CDC}.
+ */
+ protected boolean isHtmlCdc() {
+ return format == HtmlFormat.HTML_CDC;
+ }
+
+ /**
+ * Returns <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_SDC}.
+ *
+ * @return <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_SDC}.
+ */
+ protected boolean isHtmlSdc() {
+ return format == HtmlFormat.HTML_SDC;
+ }
+
+ /**
* Returns whether this bean property should not be serialized as an
HTML table.
*
* @return
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
index 439c2ea..7de6d49 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
@@ -94,6 +94,24 @@ public class HtmlClassMeta extends ClassMetaExtended {
}
/**
+ * Returns <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_CDC}.
+ *
+ * @return <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_CDC}.
+ */
+ protected boolean isHtmlCdc() {
+ return format == HtmlFormat.HTML_CDC;
+ }
+
+ /**
+ * Returns <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_SDC}.
+ *
+ * @return <jk>true</jk> if {@link #getFormat()} returns {@link
HtmlFormat#HTML_SDC}.
+ */
+ protected boolean isHtmlSdc() {
+ return format == HtmlFormat.HTML_SDC;
+ }
+
+ /**
* Returns the {@link Html#noTables() @Html.noTables()} annotation
defined on the class.
*
* @return The value of the annotation.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index 94871d3..4723e56 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -14,6 +14,7 @@ package org.apache.juneau.html;
import static org.apache.juneau.html.HtmlSerializer.*;
import static org.apache.juneau.internal.StringUtils.*;
+import static org.apache.juneau.internal.ObjectUtils.*;
import static org.apache.juneau.xml.XmlSerializerSession.ContentResult.*;
import java.io.*;
@@ -240,8 +241,9 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
type = getClassMetaForObject(o);
}
- HtmlClassMeta html = type.getExtendedMeta(HtmlClassMeta.class);
- if (type.isMapOrBean() && ! html.isXml())
+ HtmlClassMeta cHtml = cHtml(type);
+
+ if (type.isMapOrBean() && ! cHtml.isXml())
return serializeAnything(out, o, eType, elementName,
pMeta, 0, false);
return super.serializeAnything(out, o, eType, elementName,
elementNamespace, addNamespaceUris, format, isMixed, preserveWhitespace, pMeta);
@@ -322,10 +324,10 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
return ContentResult.CR_MIXED;
}
- HtmlClassMeta html =
sType.getExtendedMeta(HtmlClassMeta.class);
- HtmlRender render = (pMeta == null ? null :
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getRender());
- if (render == null)
- render = html.getRender();
+ HtmlClassMeta cHtml = cHtml(sType);
+ HtmlBeanPropertyMeta bpHtml = bpHtml(pMeta);
+
+ HtmlRender render = firstNonNull(bpHtml.getRender(),
cHtml.getRender());
if (render != null) {
Object o2 = render.getContent(this, o);
@@ -337,14 +339,14 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
}
}
- if (html.isXml() || (pMeta != null &&
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isXml())) {
+ if (cHtml.isXml() || bpHtml.isXml()) {
pop();
indent++;
super.serializeAnything(out, o, null, null,
null, false, XmlFormat.MIXED, false, false, null);
indent -= xIndent+1;
return cr;
- } else if (html.isPlainText() || (pMeta != null &&
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isPlainText())) {
+ } else if (cHtml.isPlainText() || bpHtml.isPlainText())
{
out.write(o == null ? "null" : o.toString());
cr = CR_MIXED;
@@ -418,6 +420,8 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
ClassMeta<?> keyType = eKeyType == null ? string() : eKeyType;
ClassMeta<?> valueType = eValueType == null ? object() :
eValueType;
ClassMeta<?> aType = getClassMetaForObject(m); // The
actual type
+ HtmlClassMeta cHtml = cHtml(aType);
+ HtmlBeanPropertyMeta bpHtml = bpHtml(ppMeta);
int i = indent;
@@ -427,8 +431,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.attr(getBeanTypePropertyName(sType), typeName);
out.append(">").nl(i+1);
- if (isAddKeyValueTableHeaders() && !
(aType.getExtendedMeta(HtmlClassMeta.class).isNoTableHeaders()
- || (ppMeta != null &&
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isNoTableHeaders()))) {
+ if (isAddKeyValueTableHeaders() && ! (cHtml.isNoTableHeaders()
|| bpHtml.isNoTableHeaders())) {
out.sTag(i+1, "tr").nl(i+2);
out.sTag(i+2, "th").append("key").eTag("th").nl(i+3);
out.sTag(i+2, "th").append("value").eTag("th").nl(i+3);
@@ -472,8 +475,11 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.ie(i).eTag("table").nl(i);
}
- private void serializeBeanMap(XmlWriter out, BeanMap<?> m, ClassMeta<?>
eType,
- BeanPropertyMeta ppMeta) throws Exception {
+ private void serializeBeanMap(XmlWriter out, BeanMap<?> m, ClassMeta<?>
eType, BeanPropertyMeta ppMeta) throws Exception {
+
+ HtmlClassMeta cHtml = cHtml(m.getClassMeta());
+ HtmlBeanPropertyMeta bpHtml = bpHtml(ppMeta);
+
int i = indent;
out.oTag(i, "table");
@@ -483,8 +489,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.attr(getBeanTypePropertyName(m.getClassMeta()),
typeName);
out.append('>').nl(i);
- if (isAddKeyValueTableHeaders() && !
(m.getClassMeta().getExtendedMeta(HtmlClassMeta.class).isNoTableHeaders()
- || (ppMeta != null &&
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isNoTableHeaders()))) {
+ if (isAddKeyValueTableHeaders() && ! (cHtml.isNoTableHeaders()
|| bpHtml.isNoTableHeaders())) {
out.sTag(i+1, "tr").nl(i+1);
out.sTag(i+2, "th").append("key").eTag("th").nl(i+2);
out.sTag(i+2, "th").append("value").eTag("th").nl(i+2);
@@ -544,15 +549,17 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private void serializeCollection(XmlWriter out, Object in, ClassMeta<?>
sType,
- ClassMeta<?> eType, String name, BeanPropertyMeta
ppMeta) throws Exception {
+ private void serializeCollection(XmlWriter out, Object in, ClassMeta<?>
sType, ClassMeta<?> eType, String name, BeanPropertyMeta ppMeta) throws
Exception {
- ClassMeta<?> seType = sType.getElementType();
- if (seType == null)
- seType = object();
+ HtmlClassMeta cHtml = cHtml(sType);
+ HtmlBeanPropertyMeta bpHtml = bpHtml(ppMeta);
Collection c = (sType.isCollection() ? (Collection)in :
toList(sType.getInnerClass(), in));
+ boolean isCdc = cHtml.isHtmlCdc() || bpHtml.isHtmlCdc();
+ boolean isSdc = cHtml.isHtmlSdc() || bpHtml.isHtmlSdc();
+ boolean isDc = isCdc || isSdc;
+
int i = indent;
if (c.isEmpty()) {
out.appendln(i, "<ul></ul>");
@@ -567,14 +574,13 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
c = sort(c);
- HtmlBeanPropertyMeta hbpMeta = (ppMeta == null ? null :
ppMeta.getExtendedMeta(HtmlBeanPropertyMeta.class));
String btpn = getBeanTypePropertyName(eType);
// Look at the objects to see how we're going to handle them.
Check the first object to see how we're going to
// handle this.
// If it's a map or bean, then we'll create a table.
// Otherwise, we'll create a list.
- Object[] th = getTableHeaders(c, hbpMeta);
+ Object[] th = getTableHeaders(c, bpHtml);
if (th != null) {
@@ -662,17 +668,22 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.ie(i).eTag("table").nl(i);
} else {
- out.oTag(i, "ul");
+ out.oTag(i, isDc ? "p" : "ul");
if (! type2.equals("array"))
out.attr(btpn, type2);
out.append('>').nl(i+1);
+ boolean isFirst = true;
for (Object o : c) {
- out.oTag(i+1, "li");
+ if (isDc && ! isFirst)
+ out.append(isCdc ? ", " : " ");
+ if (! isDc)
+ out.oTag(i+1, "li");
String style = getStyle(this, ppMeta, o);
String link = getLink(ppMeta);
- if (style != null)
+ if (style != null && ! isDc)
out.attr("style", style);
- out.cTag();
+ if (! isDc)
+ out.cTag();
if (link != null)
out.oTag(i+2, "a").attrUri("href",
link.replace("{#}", asString(o))).cTag();
ContentResult cr = serializeAnything(out, o,
eType.getElementType(), name, null, 1, false);
@@ -680,21 +691,22 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
out.eTag("a");
if (cr == CR_ELEMENTS)
out.ie(i+1);
- out.eTag("li").nl(i+1);
+ if (! isDc)
+ out.eTag("li").nl(i+1);
+ isFirst = false;
}
- out.ie(i).eTag("ul").nl(i);
+ out.ie(i).eTag(isDc ? "p" : "ul").nl(i);
}
}
private static HtmlRender<?> getRender(HtmlSerializerSession session,
BeanPropertyMeta pMeta, Object value) {
if (pMeta == null)
return null;
- HtmlBeanPropertyMeta hpMeta =
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);
- HtmlRender<?> render = hpMeta.getRender();
+ HtmlRender<?> render = bpHtml(pMeta).getRender();
if (render != null)
return render;
ClassMeta<?> cMeta = session.getClassMetaForObject(value);
- render = cMeta == null ? null :
cMeta.getExtendedMeta(HtmlClassMeta.class).getRender();
+ render = cMeta == null ? null : cHtml(cMeta).getRender();
return render;
}
@@ -711,6 +723,14 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
private static String getAnchorText(BeanPropertyMeta pMeta) {
return pMeta == null ? null :
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getAnchorText();
}
+
+ private static HtmlClassMeta cHtml(ClassMeta<?> cm) {
+ return cm.getExtendedMeta(HtmlClassMeta.class);
+ }
+
+ private static HtmlBeanPropertyMeta bpHtml(BeanPropertyMeta pMeta) {
+ return pMeta == null ? HtmlBeanPropertyMeta.DEFAULT :
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);
+ }
/*
* Returns the table column headers for the specified collection of
objects.
@@ -718,7 +738,7 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
* 2-dimensional tables are used for collections of objects that all
have the same set of property names.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
- private Object[] getTableHeaders(Collection c, HtmlBeanPropertyMeta
hbpMeta) throws Exception {
+ private Object[] getTableHeaders(Collection c, HtmlBeanPropertyMeta
bpHtml) throws Exception {
if (c.size() == 0)
return null;
c = sort(c);
@@ -744,10 +764,12 @@ public class HtmlSerializerSession extends
XmlSerializerSession {
return null;
if (cm.getInnerClass().isAnnotationPresent(HtmlLink.class))
return null;
- HtmlClassMeta h = cm.getExtendedMeta(HtmlClassMeta.class);
- if (h.isNoTables() || (hbpMeta != null && hbpMeta.isNoTables()))
+
+ HtmlClassMeta cHtml = cHtml(cm);
+
+ if (cHtml.isNoTables() || bpHtml.isNoTables())
return null;
- if (h.isNoTableHeaders() || (hbpMeta != null &&
hbpMeta.isNoTableHeaders()))
+ if (cHtml.isNoTableHeaders() || bpHtml.isNoTableHeaders())
return new Object[0];
if (canIgnoreValue(cm, null, o1))
return null;
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlWriter.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlWriter.java
index 8372924..5a4e100 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlWriter.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlWriter.java
@@ -79,7 +79,7 @@ public class HtmlWriter extends XmlWriter {
else if (test == ' ')
append("<sp> </sp>");
else
-
append("<sp>&#x").append(toHex(test)).append(";</sp>");
+
append("<sp>&#x").append(toHex4(test)).append(";</sp>");
}
else if (Character.isISOControl(test))
append("&#" + (int) test + ";");
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/Html.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/Html.java
index d18cf64..5e3a7d8 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/Html.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/Html.java
@@ -49,7 +49,6 @@ public @interface Html {
/**
* Specifies what format to use for the HTML element.
- *
*/
HtmlFormat format() default HtmlFormat.HTML;
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
index eef5c1e..5d0a8e6 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
@@ -30,6 +30,18 @@ public enum HtmlFormat {
HTML,
/**
+ * Object is serialized to HTML.
+ * <br>When serializing lists, use comma-delimited format instead of
list.
+ */
+ HTML_CDC,
+
+ /**
+ * Object is serialized to HTML.
+ * <br>When serializing lists, use space-delimited format instead of
list.
+ */
+ HTML_SDC,
+
+ /**
* Object is serialized to XML.
* <br>Useful when creating beans that model HTML elements.
*/
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
index 4efa915..fb7ab30 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/AsciiSet.java
@@ -44,6 +44,18 @@ public final class AsciiSet {
}
/**
+ * Copies an existing {@link AsciiSet} so that you can augment it with
additional values.
+ *
+ * @return A builder initialized to the same characters in the copied
set.
+ */
+ public AsciiSet.Builder copy() {
+ Builder b = new Builder();
+ for (int i = 0; i < 128; i++)
+ b.store[i] = store[i];
+ return b;
+ }
+
+ /**
* Builder class for {@link AsciiSet} objects.
*/
public static class Builder {
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
index 21032cd..98adf11 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ObjectUtils.java
@@ -252,7 +252,8 @@ public final class ObjectUtils {
* @param t
* @return The first non-null value, or <jk>null</jk> if the array is
null or empty or contains only <jk>null</jk> values.
*/
- public static <T> T firstNonNull(T[] t) {
+ @SafeVarargs
+ public static <T> T firstNonNull(T... t) {
if (t != null)
for (T tt : t)
if (tt != null)
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
index 694a01b..8805c10 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -49,6 +49,12 @@ public final class StringUtils {
// Characters that do not need to be URL-encoded
private static final AsciiSet unencodedChars =
AsciiSet.create().ranges("a-z","A-Z","0-9").chars("-_.!~*'()\\").build();
+ // Characters that really do not need to be URL-encoded
+ private static final AsciiSet unencodedCharsLax = unencodedChars.copy()
+ .chars(":@$,") // reserved, but can't be confused in a query
parameter.
+ .chars("{}|\\^[]`") // unwise characters.
+ .build();
+
// Maps BASE64 characters to 6-bit nibbles.
private static final byte[] base64m2 = new byte[128];
static {
@@ -909,12 +915,29 @@ public final class StringUtils {
}
/**
+ * Converts the specified number into a 2 hexadecimal characters.
+ *
+ * @param num The number to convert to hex.
+ * @return A <code><jk>char</jk>[2]</code> containing the specified
characters.
+ */
+ public static final char[] toHex2(int num) {
+ if (num < 0 || num > 255)
+ throw new NumberFormatException("toHex2 can only be
used on numbers between 0 and 255");
+ char[] n = new char[2];
+ int a = num%16;
+ n[1] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
+ a = (num/16)%16;
+ n[0] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
+ return n;
+ }
+
+ /**
* Converts the specified number into a 4 hexadecimal characters.
*
* @param num The number to convert to hex.
* @return A <code><jk>char</jk>[4]</code> containing the specified
characters.
*/
- public static final char[] toHex(int num) {
+ public static final char[] toHex4(int num) {
char[] n = new char[4];
int a = num%16;
n[3] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
@@ -928,6 +951,25 @@ public final class StringUtils {
}
/**
+ * Converts the specified number into a 8 hexadecimal characters.
+ *
+ * @param num The number to convert to hex.
+ * @return A <code><jk>char</jk>[8]</code> containing the specified
characters.
+ */
+ public static final char[] toHex8(long num) {
+ char[] n = new char[8];
+ long a = num%16;
+ n[7] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
+ int base = 16;
+ for (int i = 1; i < 8; i++) {
+ a = (num/base)%16;
+ base <<= 4;
+ n[7-i] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
+ }
+ return n;
+ }
+
+ /**
* Tests two strings for equality, but gracefully handles nulls.
*
* @param s1 String 1.
@@ -1090,6 +1132,10 @@ public final class StringUtils {
/**
* Parses an ISO8601 string into a date.
*
+ * <p>
+ * Supports any of the following formats:
+ * <br><code>yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh,
yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS</code>
+ *
* @param date The date string.
* @return The parsed date.
* @throws IllegalArgumentException
@@ -1252,7 +1298,7 @@ public final class StringUtils {
public static String unicodeSequence(char c) {
StringBuilder sb = new StringBuilder(6);
sb.append('\\').append('u');
- for (char cc : toHex(c))
+ for (char cc : toHex4(c))
sb.append(cc);
return sb.toString();
}
@@ -1655,6 +1701,40 @@ public final class StringUtils {
}
/**
+ * Same as {@link #urlEncode(String)} except only excapes characters
that absolutely need to be escaped.
+ *
+ * @param s The string to escape.
+ * @return The encoded string, or <jk>null</jk> if input is
<jk>null</jk>.
+ */
+ public static String urlEncodeLax(String s) {
+ if (s == null)
+ return null;
+ boolean needsEncode = false;
+ for (int i = 0; i < s.length() && ! needsEncode; i++)
+ needsEncode |= (!
unencodedCharsLax.contains(s.charAt(i)));
+ if (needsEncode) {
+ StringBuilder sb = new StringBuilder(s.length()*2);
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (unencodedCharsLax.contains(c))
+ sb.append(c);
+ else if (c == ' ')
+ sb.append("+");
+ else if (c <= 127)
+ sb.append('%').append(toHex2(c));
+ else
+ try {
+
sb.append(URLEncoder.encode(""+c, "UTF-8")); // Yuck.
+ } catch (UnsupportedEncodingException
e) {
+ // Not possible.
+ }
+ }
+ s = sb.toString();
+ }
+ return s;
+ }
+
+ /**
* Splits a string into equally-sized parts.
*
* @param s The string to split.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
index 5a0ae79..7b915b1 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
@@ -23,6 +23,11 @@ import org.apache.juneau.parser.*;
*/
public class JsonSchemaBeanPropertyMeta extends BeanPropertyMetaExtended {
+ /**
+ * Default instance.
+ */
+ public static final JsonSchemaBeanPropertyMeta DEFAULT = new
JsonSchemaBeanPropertyMeta();
+
private String type, format, description;
private Object example;
@@ -41,6 +46,14 @@ public class JsonSchemaBeanPropertyMeta extends
BeanPropertyMetaExtended {
if (bpm.getSetter() != null)
findInfo(bpm.getSetter().getAnnotation(JsonSchema.class));
}
+
+ private JsonSchemaBeanPropertyMeta() {
+ super(null);
+ this.type = null;
+ this.format = null;
+ this.description = null;
+ this.example = null;
+ }
private void findInfo(JsonSchema js) {
if (js == null)
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
index a8f0c05..c2103c1 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
@@ -23,6 +23,11 @@ import org.apache.juneau.xml.annotation.*;
*/
public class XmlBeanPropertyMeta extends BeanPropertyMetaExtended {
+ /**
+ * Default instance.
+ */
+ public static final XmlBeanPropertyMeta DEFAULT = new
XmlBeanPropertyMeta();
+
private Namespace namespace = null;
private XmlFormat xmlFormat = XmlFormat.DEFAULT;
private String childName;
@@ -45,6 +50,10 @@ public class XmlBeanPropertyMeta extends
BeanPropertyMetaExtended {
if (namespace == null)
namespace =
bpm.getBeanMeta().getClassMeta().getExtendedMeta(XmlClassMeta.class).getNamespace();
}
+
+ private XmlBeanPropertyMeta() {
+ super(null);
+ }
/**
* Returns the XML namespace associated with this bean property.
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index 1c563a9..b20d34d 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -181,7 +181,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
aType = push(null, o, null);
if (aType != null) {
- Namespace ns =
aType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+ Namespace ns = cXml(aType).getNamespace();
if (ns != null) {
if (ns.uri != null)
addNamespace(ns);
@@ -200,7 +200,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
bm = toBeanMap(o);
} else if (aType.isDelegate()) {
ClassMeta<?> innerType =
((Delegate<?>)o).getClassMeta();
- Namespace ns =
innerType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+ Namespace ns = cXml(innerType).getNamespace();
if (ns != null) {
if (ns.uri != null)
addNamespace(ns);
@@ -211,7 +211,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
if (innerType.isBean()) {
for (BeanPropertyMeta bpm :
innerType.getBeanMeta().getPropertyMetas()) {
if (bpm.canRead()) {
- ns =
bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+ ns =
bpXml(bpm).getNamespace();
if (ns != null &&
ns.uri != null)
addNamespace(ns);
}
@@ -238,7 +238,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
if (bm != null) {
for (BeanPropertyValue p :
bm.getValues(isTrimNulls())) {
- Namespace ns =
p.getMeta().getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+ Namespace ns =
bpXml(p.getMeta()).getNamespace();
if (ns != null && ns.uri != null)
addNamespace(ns);
@@ -362,7 +362,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
} else if (sType.isBoolean()) {
type = BOOLEAN;
} else if (sType.isMapOrBean()) {
- isCollapsed =
sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED;
+ isCollapsed = cXml(sType).getFormat() == COLLAPSED;
type = OBJECT;
} else if (sType.isCollectionOrArray()) {
isCollapsed = (format == COLLAPSED && !
addNamespaceUris);
@@ -382,9 +382,9 @@ public class XmlSerializerSession extends
WriterSerializerSession {
if (enableNamespaces) {
if (elementNamespace == null)
- elementNamespace =
sType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+ elementNamespace = cXml(sType).getNamespace();
if (elementNamespace == null)
- elementNamespace =
aType.getExtendedMeta(XmlClassMeta.class).getNamespace();
+ elementNamespace = cXml(aType).getNamespace();
if (elementNamespace != null && elementNamespace.uri ==
null)
elementNamespace = null;
if (elementNamespace == null)
@@ -546,7 +546,7 @@ public class XmlSerializerSession extends
WriterSerializerSession {
List<BeanPropertyValue> lp = m.getValues(isTrimNulls());
- XmlBeanMeta xbm = bm.getExtendedMeta(XmlBeanMeta.class);
+ XmlBeanMeta xbm = bXml(bm);
Set<String>
attrs = xbm.getAttrPropertyNames(),
@@ -576,7 +576,8 @@ public class XmlSerializerSession extends
WriterSerializerSession {
if (canIgnoreValue(cMeta, key, value))
continue;
- Namespace ns = (enableNamespaces &&
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() != elementNs ?
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() : null);
+ XmlBeanPropertyMeta bpXml =
bpXml(pMeta);
+ Namespace ns = (enableNamespaces &&
bpXml.getNamespace() != elementNs ? bpXml.getNamespace() : null);
if (pMeta.isUri() ) {
out.attrUri(ns, key, value);
@@ -643,8 +644,8 @@ public class XmlSerializerSession extends
WriterSerializerSession {
out.appendIf(! isCollapsed,
'>').nlIf(! isMixed, indent);
}
- XmlBeanPropertyMeta xbpm =
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
- serializeAnything(out, value, cMeta,
key, xbpm.getNamespace(), false, xbpm.getXmlFormat(), isMixed, false, pMeta);
+ XmlBeanPropertyMeta bpXml =
bpXml(pMeta);
+ serializeAnything(out, value, cMeta,
key, bpXml.getNamespace(), false, bpXml.getXmlFormat(), isMixed, false, pMeta);
}
}
}
@@ -685,9 +686,6 @@ public class XmlSerializerSession extends
WriterSerializerSession {
private XmlWriter serializeCollection(XmlWriter out, Object in,
ClassMeta<?> sType,
ClassMeta<?> eType, BeanPropertyMeta ppMeta, boolean
isMixed) throws Exception {
- ClassMeta<?> seType = sType.getElementType();
- if (seType == null)
- seType = object();
ClassMeta<?> eeType = eType.getElementType();
Collection c = (sType.isCollection() ? (Collection)in :
toList(sType.getInnerClass(), in));
@@ -700,9 +698,9 @@ public class XmlSerializerSession extends
WriterSerializerSession {
Namespace eNs = null;
if (ppMeta != null) {
- XmlBeanPropertyMeta xbpm =
ppMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
- eName = xbpm.getChildName();
- eNs = xbpm.getNamespace();
+ XmlBeanPropertyMeta bpXml = bpXml(ppMeta);
+ eName = bpXml.getChildName();
+ eNs = bpXml.getNamespace();
}
for (Iterator i = c.iterator(); i.hasNext();) {
@@ -712,6 +710,18 @@ public class XmlSerializerSession extends
WriterSerializerSession {
return out;
}
+ private static XmlClassMeta cXml(ClassMeta<?> cm) {
+ return cm.getExtendedMeta(XmlClassMeta.class);
+ }
+
+ private static XmlBeanPropertyMeta bpXml(BeanPropertyMeta pMeta) {
+ return pMeta == null ? XmlBeanPropertyMeta.DEFAULT :
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+ }
+
+ private static XmlBeanMeta bXml(BeanMeta bm) {
+ return (XmlBeanMeta)bm.getExtendedMeta(XmlBeanMeta.class);
+ }
+
static enum JsonType {
STRING("string"),BOOLEAN("boolean"),NUMBER("number"),ARRAY("array"),OBJECT("object"),NULL("null");
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlUtils.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlUtils.java
index 96fcb3e..cc01222 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlUtils.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlUtils.java
@@ -473,7 +473,7 @@ public final class XmlUtils {
// Converts an integer to a hexadecimal string padded to 4 places.
private static final Writer appendPaddedHexChar(Writer out, int num)
throws IOException {
out.append("_x");
- for (char c : toHex(num))
+ for (char c : toHex4(num))
out.append(c);
return out.append('_');
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
index 6c68c4e..05f5f95 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
@@ -351,8 +351,8 @@ public class XmlSchemaSerializerSession extends
XmlSerializerSession {
for (BeanPropertyMeta pMeta :
bm.getPropertyMetas()) {
if (pMeta.canRead()) {
- XmlFormat pMetaFormat =
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
- if (pMetaFormat !=
XmlFormat.ATTR)
+ XmlFormat bpXml =
pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
+ if (bpXml !=
XmlFormat.ATTR)
hasChildElements = true;
}
}
diff --git a/juneau-doc/src/main/javadoc/overview.html
b/juneau-doc/src/main/javadoc/overview.html
index 931684b..0264198 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -9051,7 +9051,7 @@
Both kinds of objects are accessible through the
following method:
</p>
<ul>
- <li class='jm'>{@link
org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String)}
+ <li class='jm'>{@link
org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String,
boolean)}
</ul>
<p>
Var resolvers can be cloned and extended by using the
{@link org.apache.juneau.svl.VarResolver#builder()} method.
@@ -21358,6 +21358,12 @@
<li>
New option for dyna-property (i.e.
<code><ja>@Bean</ja>(<js>"*"</js>)</code>) using a method that returns a
collection of extra keys.
<br>See new options #4 on {@link
org.apache.juneau.annotation.BeanProperty#name()}
+ <li>
+ New formats for the {@link
org.apache.juneau.html.annotation.Html#format() @Html.format()} annotation:
+ <ul>
+ <li class='jf'>{@link
org.apache.juneau.html.annotation.HtmlFormat#HTML_CDC} - Format collections as
comma-delimited lists.
+ <li class='jf'>{@link
org.apache.juneau.html.annotation.HtmlFormat#HTML_SDC} - Format collections as
space-delimited lists.
+ </ul>
</ul>
<h5 class='topic w800'>juneau-dto</h5>
@@ -21460,9 +21466,23 @@
<li class='jc'>{@link
org.apache.juneau.parser.ReaderParser} - The reader parser matching the request
content type.
<li class='jc'>{@link
org.apache.juneau.parser.InputStreamParser} - The input stream parser matching
the request content type.
</ul>
+ <li>
+ The <code>$F</code> variable can now be used as
a initialization time variable.
+ <br>For example, the
<code>AtomFeedResource</code> example pulls a bean example from a file on the
classpath:
+ <p class='bcode'>
+ <ja>@RestResource</ja>(
+ path=<js>"/atom"</js>,
+ title=<js>"Sample ATOM feed resource"</js>,
+ properties={
+ <ja>@Property</ja>(name=<jsf>BEAN_examples</jsf>,
value=<js>"{'org.apache.juneau.dto.atom.Feed':
$F{AtomFeedResource_example.json}}"</js>)
+ },
+ ...
+ )
+ </p>
+ <br>It should be noted that you cannot use the
<code>$F</code> variable to retrieve localized versions of files (since you're
not within
+ the scope of a client request.
</ul>
-
- <h5 class='topic w800'>juneau-rest-client</h5>
+
<ul class='spaced-list'>
<li>
Made improvements to the builder API for
defining SSL support.
diff --git a/juneau-examples/juneau-examples-rest/examples.cfg
b/juneau-examples/juneau-examples-rest/examples.cfg
index e869a35..23d9f06 100755
--- a/juneau-examples/juneau-examples-rest/examples.cfg
+++ b/juneau-examples/juneau-examples-rest/examples.cfg
@@ -95,12 +95,10 @@ logDir = ./target/logs
logFile = microservice.%g.log
# Whether to append to the existing log file or create a new one.
-# Default is false.
-append =
+append = false
# The SimpleDateFormat format to use for dates.
-# Default is "yyyy.MM.dd hh:mm:ss".
-dateFormat =
+dateFormat = yyyy.MM.dd hh:mm:ss
# The log message format.
# The value can contain any of the following variables:
@@ -112,17 +110,14 @@ dateFormat =
# {msg} - The log message.
# {threadid} - The thread ID.
# {exception} - The localized exception message.
-# Default is "[{date} {level}] {msg}%n".
-format =
+format = [{date} {level}] {msg}%n
# The maximum log file size.
# Suffixes available for numbers.
# See Config.getInt(String,int) for details.
-# Default is 1M.
-limit = 10M
+limit = 1M
# Max number of log files.
-# Default is 1.
count = 5
# Default log levels.
@@ -138,12 +133,10 @@ levels =
# Only print unique stack traces once and then refer to them by a simple 8
character hash identifier.
# Useful for preventing log files from filling up with duplicate stack traces.
-# Default is false.
useStackTraceHashes = true
# The default level for the console logger.
# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE,
FINER, FINEST)
-# Default is WARNING.
consoleLevel = WARNING
# The default level for the file logger.
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
index 50b20d9..07839df 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/JsonSchemaResource.java
@@ -12,6 +12,7 @@
//
***************************************************************************************************************************
package org.apache.juneau.examples.rest;
+import static org.apache.juneau.BeanContext.*;
import static org.apache.juneau.http.HttpMethodName.*;
import org.apache.juneau.dto.jsonschema.*;
@@ -27,6 +28,9 @@ import org.apache.juneau.rest.widget.*;
messages="nls/JsonSchemaResource",
title="Sample JSON-Schema document",
description="Sample resource that shows how to generate JSON-Schema
documents",
+ properties={
+ @Property(name=BEAN_examples,
value="{'org.apache.juneau.dto.jsonschema.Schema':
$F{JsonSchemaResource_example.json}}")
+ },
htmldoc=@HtmlDoc(
widgets={
ContentTypeMenuItem.class,
@@ -82,17 +86,21 @@ public class JsonSchemaResource extends
BasicRestServletJena {
}
}
- /** GET request handler */
- @RestMethod(name=GET, path="/", summary="Get the JSON-Schema document")
+ @RestMethod(
+ name=GET,
+ path="/",
+ summary="Get the JSON-Schema document"
+ )
public Schema getSchema() throws Exception {
return schema;
}
- /**
- * PUT request handler.
- * Replaces the schema document with the specified content, and then
mirrors it as the response.
- */
- @RestMethod(name=PUT, path="/", summary="Overwrite the JSON-Schema
document")
+ @RestMethod(
+ name=PUT,
+ path="/",
+ summary="Overwrite the JSON-Schema document",
+ description="Replaces the schema document with the specified
content, and then mirrors it as the response."
+ )
public Schema setSchema(@Body Schema schema) throws Exception {
this.schema = schema;
return schema;
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
index e5697a3..8d5290b 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
@@ -76,7 +76,6 @@ import org.apache.juneau.rest.widget.*;
LogsResource.class,
DockerRegistryResource.class,
PredefinedLabelsResource.class,
- StaticFilesResource.class,
DebugResource.class,
ShutdownResource.class
}
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
index f34839a..78e6e21 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SqlQueryResource.java
@@ -43,7 +43,7 @@ import org.apache.juneau.rest.widget.*;
},
navlinks={
"up: request:/..",
- "options: servlet:/..",
+ "options: servlet:/?method=OPTIONS",
"$W{ThemeMenuItem}",
"source:
$C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
},
@@ -93,9 +93,15 @@ public class SqlQueryResource extends BasicRestServlet {
}
}
- /** GET request handler - Display the query entry page. */
- @RestMethod(name=GET, path="/", summary="Display the query entry page")
- public Div doGet(RestRequest req, @Query("sql") String sql) {
+ @RestMethod(
+ name=GET,
+ path="/",
+ summary="Display the query entry page"
+ )
+ public Div doGet(
+ @Query(name="sql", description="Text to prepopulate the
SQL query field with.", example="select * from sys.systables") String sql
+ ) {
+
return div(
script("text/javascript",
"\n // Quick and dirty function to allow
tabs in textarea."
@@ -117,9 +123,9 @@ public class SqlQueryResource extends BasicRestServlet {
form("servlet:/").method(POST).target("buf").children(
table(
tr(
- th("Position (1-10000):"),
+ th("Position
(1-10000):").style("white-space:nowrap"),
td(input().name("pos").type("number").value(1)),
- th("Limit (1-10000):"),
+ th("Limit
(1-10000):").style("white-space:nowrap"),
td(input().name("limit").type("number").value(100)),
td(button("submit", "Submit"),
button("reset", "Reset"))
),
@@ -136,9 +142,19 @@ public class SqlQueryResource extends BasicRestServlet {
);
}
- /** POST request handler - Execute the query. */
- @RestMethod(name=POST, path="/", summary="Execute one or more queries")
- public List<Object> doPost(@Body PostInput in) throws BadRequest {
+ @RestMethod(
+ name=POST,
+ path="/",
+ summary="Execute one or more queries",
+ swagger= {
+ "responses:{",
+ "200:{ description:'Query results.\nEach entry
in the array is a result of one query.\nEach result can be a result set (for
queries) or update count (for updates).',
'x-example':[[{col1:'val1'},{col2:'val2'},{col3:'val3'}],123]}",
+ "}",
+ }
+ )
+ public List<Object> doPost(
+ @Body(description="Query input", example="{sql:'select
* from sys.systables',pos:1,limit:100}") PostInput in
+ ) throws BadRequest {
List<Object> results = new LinkedList<>();
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/StaticFilesResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/StaticFilesResource.java
deleted file mode 100644
index a501b45..0000000
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/StaticFilesResource.java
+++ /dev/null
@@ -1,83 +0,0 @@
-//
***************************************************************************************************************************
-// * 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.examples.rest;
-
-import static org.apache.juneau.http.HttpMethodName.*;
-
-import org.apache.juneau.dto.*;
-import org.apache.juneau.dto.swagger.*;
-import org.apache.juneau.dto.swagger.ui.*;
-import org.apache.juneau.http.*;
-import org.apache.juneau.microservice.*;
-import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.widget.*;
-
-/**
- * Sample resource that shows how to generate ATOM feeds.
- */
-@RestResource(
- path="/staticFiles",
- title="SwaggerUI testbed",
- description="Sample resource that shows how to use static files.",
- htmldoc=@HtmlDoc(
- widgets={
- ContentTypeMenuItem.class,
- ThemeMenuItem.class
- },
- navlinks={
- "up: request:/..",
- "options: servlet:/?method=OPTIONS",
- "$W{ContentTypeMenuItem}",
- "$W{ThemeMenuItem}",
- "source:
$C{Source/gitHub}/org/apache/juneau/examples/rest/$R{staticFilesResource}.java"
- }
- ),
- staticFiles= {
- // Serve up files in /files under the child URI /static
- "static:files"
- },
- swagger={
- "info: {",
- "contact:{name:'Juneau
Developer',email:'[email protected]'},",
- "license:{name:'Apache
2.0',url:'http://www.apache.org/licenses/LICENSE-2.0.html'},",
- "version:'2.0',",
- "termsOfService:'You are on your own.'",
- "},",
- "externalDocs:{description:'Apache
Juneau',url:'http://juneau.apache.org'}"
- }
-)
-public class StaticFilesResource extends BasicRestServletJena {
- private static final long serialVersionUID = 1L;
-
- /**
- * GET request handler
- */
- @RestMethod(name=GET, path="/", summary="Get the sample ATOM feed")
- public LinkString[] getFiles() throws Exception {
- return new LinkString[] {
- new LinkString("petstore.html","static/petstore.html")
- };
- }
-
- @RestMethod(name=GET, path="/swagger", summary="Normal")
- public Swagger testSwagger() throws Exception {
- Swagger s = getContext().getClasspathResource(Swagger.class,
MediaType.JSON, "files/petstore.json", null);
- return s;
- }
-
- @RestMethod(name=GET, path="/swagger2", summary="SwaggerUI",
pojoSwaps=SwaggerUI.class)
- public Swagger testSwagger2() throws Exception {
- Swagger s = getContext().getClasspathResource(Swagger.class,
MediaType.JSON, "files/petstore.json", null);
- return s;
- }
-}
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
index 79d3fb3..baa58a8 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/TempDirResource.java
@@ -15,6 +15,7 @@ package org.apache.juneau.examples.rest;
import static org.apache.juneau.dto.html5.HtmlBuilder.*;
import static org.apache.juneau.http.HttpMethodName.*;
import static org.apache.juneau.rest.annotation.HookEvent.*;
+import static org.apache.juneau.microservice.resources.DirectoryResource.*;
import java.io.*;
@@ -57,10 +58,10 @@ import org.apache.juneau.utils.*;
}
),
properties={
- @Property(name="DirectoryResource.rootDir",
value="$C{TempDirResource/dir,$S{java.io.tmpdir}}"),
- @Property(name="DirectoryResource.allowViews", value="true"),
- @Property(name="DirectoryResource.allowDeletes", value="true"),
- @Property(name="DirectoryResource.allowPuts", value="false")
+ @Property(name=DIRECTORY_RESOURCE_rootDir,
value="$C{TempDirResource/dir,$S{java.io.tmpdir}}"),
+ @Property(name=DIRECTORY_RESOURCE_allowViews, value="true"),
+ @Property(name=DIRECTORY_RESOURCE_allowDeletes, value="true"),
+ @Property(name=DIRECTORY_RESOURCE_allowUploads, value="false")
},
swagger={
"info: {",
diff --git
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
index 8013dd0..2da113e 100644
---
a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
+++
b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/UrlEncodedFormResource.java
@@ -67,6 +67,7 @@ public class UrlEncodedFormResource extends BasicRestServlet {
path="/",
htmldoc=@HtmlDoc(
script={
+ "INHERIT",
"// Load results from IFrame into this
document.",
"function loadResults(buff) {",
" var doc = buff.contentDocument ||
buff.contentWindow.document;",
@@ -81,16 +82,16 @@ public class UrlEncodedFormResource extends
BasicRestServlet {
form().id("form").action("servlet:/").method(POST).target("buff").children(
table(
tr(
- th(req.getMessage("aString")),
-
td(input().name("aString").type("text"))
+
th(req.getMessage("aString")).style("white-space:nowrap"),
+
td(input().name("aString").type("text").size(50))
),
tr(
- th(req.getMessage("aNumber")),
-
td(input().name("aNumber").type("number"))
+
th(req.getMessage("aNumber")).style("white-space:nowrap"),
+
td(input().name("aNumber").type("number").size(50))
),
tr(
- th(req.getMessage("aDate")),
-
td(input().name("aDate").type("datetime"), br(), "ISO8601", br(),
code("2001-07-04T15:30:45Z"))
+
th(req.getMessage("aDate")).style("white-space:nowrap"),
+
td(input().name("aDate").type("datetime-local").size(50).value("2001-07-04T15:30:45"),
br(), "ISO8601", code("")).style("white-space:nowrap")
),
tr(
td().colspan(2).style("text-align:right").children(
diff --git
a/juneau-examples/juneau-examples-rest/src/main/resources/examples.cfg
b/juneau-examples/juneau-examples-rest/src/main/resources/examples.cfg
deleted file mode 100755
index d6d0e6a..0000000
--- a/juneau-examples/juneau-examples-rest/src/main/resources/examples.cfg
+++ /dev/null
@@ -1,147 +0,0 @@
-#
***************************************************************************************************************************
-# * 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.
*
-#
***************************************************************************************************************************
-
-#================================================================================
-# Basic configuration file for SaaS microservices
-# Subprojects can use this as a starting point.
-#================================================================================
-
-#================================================================================
-# REST settings
-#================================================================================
-[REST]
-
-port = 10000
-
-# Authentication: NONE, BASIC.
-authType = NONE
-
-# The BASIC auth username, password, and realm
-loginUser =
-loginPassword =
-authRealm =
-
-# Stylesheet to use for HTML views.
-# The default options are:
-# - styles/juneau.css
-# - styles/devops.css
-# Other stylesheets can be referenced relative to the servlet package or
working
-# directory.
-stylesheet = styles/devops.css
-
-# What to do when the config file is saved.
-# Possible values:
-# NOTHING - Don't do anything.
-# RESTART_SERVER - Restart the Jetty server.
-# RESTART_SERVICE - Shutdown and exit with code '3'.
-saveConfigAction = RESTART_SERVER
-
-# Enable SSL support.
-useSsl = false
-
-#================================================================================
-# Bean properties on the org.eclipse.jetty.util.ssl.SslSocketFactory class
-#--------------------------------------------------------------------------------
-# Ignored if REST/useSsl is false.
-# Specify any of the following fields:
-# allowRenegotiate (boolean)
-# certAlias (String)
-# crlPath (String)
-# enableCRLDP (boolean)
-# enableOCSP (boolean)
-# excludeCipherSuites (String[])
-# excludeProtocols (String[])
-# includeCipherSuites (String[])
-# includeProtocols (String...)
-# keyManagerPassword (String)
-# keyStore (String)
-# keyStorePassword (String)
-# keyStorePath (String)
-# keyStoreProvider (String)
-# keyStoreType (String)
-# maxCertPathLength (int)
-# needClientAuth (boolean)
-# ocspResponderURL (String)
-# protocol (String)
-# provider (String)
-# secureRandomAlgorithm (String)
-# sessionCachingEnabled (boolean)
-# sslKeyManagerFactoryAlgorithm (String)
-# sslSessionCacheSize (int)
-# sslSessionTimeout (int)
-# trustAll (boolean)
-# trustManagerFactoryAlgorithm (String)
-# trustStore (String)
-# trustStorePassword (String)
-# trustStoreProvider (String)
-# trustStoreType (String)
-# validateCerts (boolean)
-# validatePeerCerts (boolean)
-# wantClientAuth (boolean)
-#================================================================================
-[REST-SslContextFactory]
-keyStorePath = client_keystore.jks
-keyStorePassword* = {HRAaRQoT}
-excludeCipherSuites = TLS_DHE.*, TLS_EDH.*
-excludeProtocols = SSLv3
-allowRenegotiate = false
-
-#================================================================================
-# Logger settings
-# See FileHandler Java class for details.
-#================================================================================
-[Logging]
-logDir = logs
-logFile = sample.%g.log
-dateFormat = yyyy.MM.dd hh:mm:ss
-format = [{date} {level}] {msg}%n
-append = false
-limit = 10M
-count = 5
-levels = { org.apache.juneau:'INFO' }
-useStackTraceHashes = true
-consoleLevel = WARNING
-
-#================================================================================
-# System properties
-#--------------------------------------------------------------------------------
-# These are arbitrary system properties that can be set during startup.
-#================================================================================
-[SystemProperties]
-
-# Configure Jetty for StdErrLog Logging
-org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
-
-# Jetty logging level
-org.eclipse.jetty.LEVEL = WARN
-
-#================================================================================
-# DockerRegistryResource properties
-#================================================================================
-[DockerRegistry]
-url = http://docker.apache.org:5000/v1
-
-#================================================================================
-# SqlQueryResource properties
-#================================================================================
-[SqlQueryResource]
-driver = org.apache.derby.jdbc.EmbeddedDriver
-connectionUrl = jdbc:derby:C:/testDB;create=true
-allowTempUpdates = true
-includeRowNums = true
-
-#================================================================================
-# Source code location
-#================================================================================
-[Source]
-gitHub =
https://github.com/apache/juneau/blob/master/juneau-examples-rest/src/main/java
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/JsonSchemaResource_example.json
similarity index 70%
copy from
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
copy to
juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/JsonSchemaResource_example.json
index eef5c1e..d5bdc95 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/annotation/HtmlFormat.java
+++
b/juneau-examples/juneau-examples-rest/src/main/resources/org/apache/juneau/examples/rest/JsonSchemaResource_example.json
@@ -2,7 +2,7 @@
// * 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
*
+// * with the License. You may obtain a copy of the License at
*
// *
*
// * http://www.apache.org/licenses/LICENSE-2.0
*
// *
*
@@ -10,28 +10,26 @@
// * "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.html.annotation;
-
-/**
- * Possible values for the {@link Html#format()} annotation.
- */
-public enum HtmlFormat {
-
- /**
- * Object is serialized to a String using the <code>toString()</code>
method and written directly to output.
- * <br>Useful when you want to serialize custom HTML.
- */
- PLAIN_TEXT,
-
- /**
- * Object is serialized to HTML.
- * <br>This is the default value for serialization.
- */
- HTML,
-
- /**
- * Object is serialized to XML.
- * <br>Useful when creating beans that model HTML elements.
- */
- XML
-}
+{
+ id: 'http://example.com/sample-schema#',
+ '$schema': 'http://json-schema.org/draft-04/schema#',
+ title: 'Example Schema',
+ type: 'object',
+ properties: {
+ firstName: {
+ type: 'string'
+ },
+ lastName: {
+ type: 'string'
+ },
+ age: {
+ description: 'Age in years',
+ type: 'integer',
+ minimum: 0
+ }
+ },
+ required: [
+ 'firstName',
+ 'lastName'
+ ]
+}
\ No newline at end of file
diff --git
a/juneau-examples/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/TestMultiPartFormPostsTest.java
b/juneau-examples/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/TestMultiPartFormPostsTest.java
index 7f43edd..96c847c 100644
---
a/juneau-examples/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/TestMultiPartFormPostsTest.java
+++
b/juneau-examples/juneau-examples-rest/src/test/java/org/apache/juneau/examples/rest/TestMultiPartFormPostsTest.java
@@ -41,7 +41,7 @@ public class TestMultiPartFormPostsTest extends RestTestcase {
HttpEntity entity =
MultipartEntityBuilder.create().addBinaryBody(f.getName(), f).build();
client.doPost(URL + "/upload", entity);
- String downloaded = client.doGet(URL + "/file/" + f.getName() +
"?method=VIEW").getResponseAsString();
+ String downloaded = client.doGet(URL + "/" + f.getName() +
"?method=VIEW").getResponseAsString();
assertEquals("test!", downloaded);
}
}
\ No newline at end of file
diff --git
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
index 0803bab..27863c1 100755
---
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
+++
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/ConfigResource.java
@@ -41,29 +41,32 @@ import org.apache.juneau.rest.exception.*;
}
)
)
+@SuppressWarnings("javadoc")
public class ConfigResource extends BasicRestServlet {
private static final long serialVersionUID = 1L;
-
- /**
- * [GET /] - Show contents of config file.
- *
- * @return The config file.
- * @throws Exception
- */
- @RestMethod(name=GET, path="/", description="Show contents of config
file.")
- public ObjectMap getConfig() throws Exception {
+
+ @RestMethod(
+ name=GET,
+ path="/",
+ summary="Get config file contents",
+ description="Show contents of config file as an ObjectMap.",
+ swagger={
+ "responses:{",
+ "200:{ description:'Config file as a map of map
of objects.',
'x-example':{'':{defaultKey:'defaultValue'},'Section1':{key1:'val1',key2:123}}}",
+ "}",
+ }
+ )
+ public ObjectMap getConfig() {
return getServletConfig().getConfig().asMap();
}
- /**
- * [GET /edit] - Show config file edit page.
- *
- * @param req The HTTP request.
- * @return The config file as a reader resource.
- * @throws Exception
- */
- @RestMethod(name=GET, path="/edit", description="Edit config file.")
- public Form getConfigEditForm(RestRequest req) throws Exception {
+ @RestMethod(
+ name=GET,
+ path="/edit",
+ summary="Render form entry page for editing config file",
+ description="Renders a form entry page for editing the raw text
of a config file."
+ )
+ public Form getConfigEditForm() {
return
form().id("form").action("servlet:/").method("POST").enctype("application/x-www-form-urlencoded").children(
div()._class("data").children(
table(
@@ -78,140 +81,158 @@ public class ConfigResource extends BasicRestServlet {
);
}
- /**
- * [GET /{section}] - Show config file section.
- *
- * @param section The section name.
- * @return The config file section.
- * @throws Exception
- */
- @RestMethod(name=GET, path="/{section}",
- description="Show config file section.",
+ @RestMethod(
+ name=GET,
+ path="/{section}",
+ summary="Get config file section contents",
+ description="Show contents of config file section as an
ObjectMap.",
swagger={
- "parameters:[",
- "{name:'section',in:'path',description:'Section
name.'}",
- "]"
+ "responses:{",
+ "200:{ description:'Config file section as a
map of objects.', 'x-example':{key1:'val1',key2:123}}",
+ "}",
}
)
- public ObjectMap getConfigSection(@Path("section") String section)
throws Exception {
+ public ObjectMap getConfigSection(
+ @Path(name="section", description="Section name in
config file.", example="REST") String section
+ ) throws SectionNotFound, BadConfig {
+
return getSection(section);
}
- /**
- * [GET /{section}/{key}] - Show config file entry.
- *
- * @param section The section name.
- * @param key The section key.
- * @return The value of the config file entry.
- * @throws Exception
- */
- @RestMethod(name=GET, path="/{section}/{key}",
- description="Show config file entry.",
+ @RestMethod(
+ name=GET,
+ path="/{section}/{key}",
+ summary="Get config file entry value",
+ description="Show value of config file entry as a simple
string.",
swagger={
- "parameters:[",
- "{name:'section',in:'path',description:'Section
name.'},",
- "{name:'key',in:'path',description:'Entry
name.'}",
- "]"
+ "responses:{",
+ "200:{ description:'Entry value.',
'x-example':'servlet:/htdocs/themes/dark.css'}",
+ "}",
}
)
- public String getConfigEntry(@Path("section") String section,
@Path("key") String key) throws Exception {
+ public String getConfigEntry(
+ @Path(name="section", description="Section name in
config file.", example="REST") String section,
+ @Path(name="key", description="Key name in section.",
example="theme") String key
+ ) throws SectionNotFound, BadConfig {
+
return getSection(section).getString(key);
}
- /**
- * [POST /] - Sets contents of config file from a FORM post.
- *
- * @param contents The new contents of the config file.
- * @return The new config file contents.
- * @throws Exception
- */
- @RestMethod(name=POST, path="/",
- description="Sets contents of config file from a FORM post.",
+ @RestMethod(
+ name=POST,
+ path="/",
+ summary="Update config file contents",
+ description="Update the contents of the config file from a FORM
post.",
swagger={
- "parameters:[",
-
"{name:'contents',in:'formData',description:'New contents in INI file
format.'}",
- "]"
+ "responses:{",
+ "200:{ description:'Config file section as a
map of objects.', 'x-example':{key1:'val1',key2:123}}",
+ "}",
}
)
- public ObjectMap setConfigContentsFormPost(@FormData("contents") String
contents) throws Exception {
+ public ObjectMap setConfigContentsFormPost(
+ @FormData(name="contents", description="New contents in
INI file format.") String contents
+ ) throws Exception {
+
return setConfigContents(new StringReader(contents));
}
- /**
- * [PUT /] - Sets contents of config file.
- *
- * @param contents The new contents of the config file.
- * @return The new config file contents.
- * @throws Exception
- */
- @RestMethod(name=PUT, path="/",
- description="Sets contents of config file.",
+ @RestMethod(
+ name=PUT,
+ path="/",
+ summary="Update config file contents",
+ description="Update the contents of the config file from raw
text.",
swagger={
- "parameters:[",
- "{in:'body',description:'New contents in INI
file format.'}",
- "]"
+ "responses:{",
+ "200:{ description:'Config file section as a
map of objects.', 'x-example':{key1:'val1',key2:123}}",
+ "}",
}
)
- public ObjectMap setConfigContents(@Body Reader contents) throws
Exception {
+ public ObjectMap setConfigContents(
+ @Body(description="New contents in INI file format.")
Reader contents
+ ) throws Exception {
+
return getServletConfig().getConfig().load(contents,
true).asMap();
}
- /**
- * [PUT /{section}] - Add or overwrite a config file section.
- *
- * @param section The section name.
- * @param contents The new contents of the config file section.
- * @return The new section.
- * @throws Exception
- */
- @RestMethod(name=PUT, path="/{section}",
+ @RestMethod(
+ name=PUT,
+ path="/{section}",
+ summary="Update config section contents",
description="Add or overwrite a config file section.",
swagger={
- "parameters:[",
- "{name:'section',in:'path',description:'Section
name.'},",
- "{in:'body',description:'New contents for
section as a simple map with string keys and values.'}",
- "]"
+ "responses:{",
+ "200:{ description:'Config file section as a
map of objects.', 'x-example':{key1:'val1',key2:123}}",
+ "}",
}
)
- public ObjectMap setConfigSection(@Path("section") String section,
@Body Map<String,Object> contents) throws Exception {
+ public ObjectMap setConfigSection(
+ @Path(name="section", description="Section name in
config file.", example="REST") String section,
+ @Body(
+ description="New contents of config section as
a simple map of key/value pairs.",
+
example="{theme:'servlet:/htdocs/themes/dark.css'}"
+ ) Map<String,Object> contents
+ ) throws Exception {
+
getServletConfig().getConfig().setSection(section, null,
contents);
return getSection(section);
}
- /**
- * [PUT /{section}/{key}] - Add or overwrite a config file entry.
- *
- * @param section The section name.
- * @param key The section key.
- * @param value The new value.
- * @return The new value.
- * @throws NotFound Thrown if config section not found.
- * @throws BadRequest Thrown if contents are not valid.
- */
- @RestMethod(name=PUT, path="/{section}/{key}",
+ @RestMethod(
+ name=PUT,
+ path="/{section}/{key}",
+ summary="Update config entry value",
description="Add or overwrite a config file entry.",
swagger={
- "parameters:[",
- "{name:'section',in:'path',description:'Section
name.'},",
- "{name:'key',in:'path',description:'Entry
name.'},",
- "{in:'body',description:'New value as a
string.'}",
- "]"
+ "responses:{",
+ "200:{ description:'The updated value.',
'x-example':'servlet:/htdocs/themes/dark.css'}",
+ "}",
}
)
- public String setConfigSection(@Path("section") String section,
@Path("key") String key, @Body String value) throws NotFound, BadRequest {
+ public String setConfigValue(
+ @Path(name="section", description="Section name in
config file.", example="REST") String section,
+ @Path(name="key", description="Key name in section.",
example="theme") String key,
+ @Body(description="New value for entry.",
example="servlet:/htdocs/themes/dark.css") String value
+ ) throws SectionNotFound, BadConfig {
+
getServletConfig().getConfig().set(section + '/' + key, value);
return getSection(section).getString(key);
}
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Helper beans
+
//-----------------------------------------------------------------------------------------------------------------
+
+ @ResponseInfo(description="Section not found.")
+ private class SectionNotFound extends NotFound {
+ private static final long serialVersionUID = 1L;
+
+ SectionNotFound() {
+ super("Section not found.");
+ }
+ }
+
+ @ResponseInfo(description="The configuration file contained syntax
errors and could not be parsed.")
+ private class BadConfig extends InternalServerError {
+ private static final long serialVersionUID = 1L;
+
+ BadConfig(Exception e) {
+ super(e, "The configuration file contained syntax
errors and could not be parsed.");
+ }
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Helper methods
+
//-----------------------------------------------------------------------------------------------------------------
- private ObjectMap getSection(String name) throws NotFound, BadRequest {
+ private ObjectMap getSection(String name) throws SectionNotFound,
BadConfig {
ObjectMap m;
try {
m =
getServletConfig().getConfig().getSectionAsMap(name);
} catch (ParseException e) {
- throw new BadRequest(e, "Invalid input");
+ throw new BadConfig(e);
}
if (m == null)
- throw new NotFound("Section not found.");
+ throw new SectionNotFound();
return m;
}
}
diff --git
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
index 9d50ec6..2e10ed3 100755
---
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
+++
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
@@ -12,22 +12,19 @@
//
***************************************************************************************************************************
package org.apache.juneau.microservice.resources;
-import static java.util.logging.Level.*;
import static org.apache.juneau.html.HtmlDocSerializer.*;
import static org.apache.juneau.http.HttpMethodName.*;
import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.rest.annotation.HookEvent.*;
import java.io.*;
-import java.net.URI;
import java.util.*;
-import java.util.logging.*;
import org.apache.juneau.annotation.*;
import org.apache.juneau.dto.*;
+import org.apache.juneau.html.annotation.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.converters.*;
import org.apache.juneau.rest.exception.*;
import org.apache.juneau.rest.helper.*;
import org.apache.juneau.transforms.*;
@@ -51,7 +48,7 @@ import org.apache.juneau.utils.*;
* <li>
* <l>DirectoryResource.allowViews</l> - If <jk>true</jk>, allows
view and download access to files.
* <li>
- * <l>DirectoryResource.allowPuts</l> - If <jk>true</jk>, allows
files to be created or overwritten.
+ * <l>DirectoryResource.allowUploads</l> - If <jk>true</jk>,
allows files to be created or overwritten.
* <li>
* <l>DirectoryResource.allowDeletes</l> - If <jk>true</jk>,
allows files to be deleted.
* </ul>
@@ -67,102 +64,126 @@ import org.apache.juneau.utils.*;
),
allowedMethodParams="*",
properties={
- @Property(name=HTML_uriAnchorText, value="PROPERTY_NAME"),
- @Property(name="DirectoryResource.rootDir", value="")
+ @Property(name=HTML_uriAnchorText, value="PROPERTY_NAME")
}
)
@SuppressWarnings("javadoc")
public class DirectoryResource extends BasicRestServlet {
private static final long serialVersionUID = 1L;
+
//-------------------------------------------------------------------------------------------------------------------
+ // Configurable properties
+
//-------------------------------------------------------------------------------------------------------------------
+
+ private static final String PREFIX = "DirectoryResource.";
+
+ /**
+ * Configuration property: Root directory.
+ */
+ public static final String DIRECTORY_RESOURCE_rootDir = PREFIX +
"rootDir.s";
+
+ /**
+ * Configuration property: Allow view and downloads on files.
+ */
+ public static final String DIRECTORY_RESOURCE_allowViews = PREFIX +
"allowViews.b";
+
+ /**
+ * Configuration property: Allow deletes on files.
+ */
+ public static final String DIRECTORY_RESOURCE_allowDeletes = PREFIX +
"allowDeletes.b";
+
+ /**
+ * Configuration property: Allow uploads on files.
+ */
+ public static final String DIRECTORY_RESOURCE_allowUploads = PREFIX +
"allowUploads.b";
+
+
+
//-------------------------------------------------------------------------------------------------------------------
+ // Instance
+
//-------------------------------------------------------------------------------------------------------------------
+
private File rootDir; // The root directory
// Settings enabled through servlet init parameters
- boolean allowDeletes, allowPuts, allowViews;
-
- private static Logger logger =
Logger.getLogger(DirectoryResource.class.getName());
+ boolean allowDeletes, allowUploads, allowViews;
@RestHook(INIT)
public void init(RestContextBuilder b) throws Exception {
RestContextProperties p = b.getProperties();
- rootDir = new File(p.getString("DirectoryResource.rootDir"));
- allowViews = p.getBoolean("DirectoryResource.allowViews",
false);
- allowDeletes = p.getBoolean("DirectoryResource.allowDeletes",
false);
- allowPuts = p.getBoolean("DirectoryResource.allowPuts", false);
- }
-
- /**
- * Returns the root directory defined by the 'rootDir' init parameter.
- *
- * <p>
- * Subclasses can override this method to provide their own root
directory.
- *
- * @return The root directory.
- */
- protected File getRootDir() {
- if (rootDir == null) {
- rootDir = new
File(getProperties().getString("rootDir"));
- if (! rootDir.exists())
- if (! rootDir.mkdirs())
- throw new RuntimeException("Could not
create root dir");
- }
- return rootDir;
+ rootDir = new File(p.getString(DIRECTORY_RESOURCE_rootDir));
+ allowViews = p.getBoolean(DIRECTORY_RESOURCE_allowViews, false);
+ allowDeletes = p.getBoolean(DIRECTORY_RESOURCE_allowDeletes,
false);
+ allowUploads = p.getBoolean(DIRECTORY_RESOURCE_allowUploads,
false);
}
@RestMethod(
name=GET,
path="/*",
- summary="View files on directory",
- description="Returns a listing of all files in the specified
directory.",
- converters={Queryable.class},
+ summary="View information on file or directory",
+ description="Returns information about the specified file or
directory.",
htmldoc=@HtmlDoc(
- nav={"<h5>Folder: $RA{fullPath}</h5>"}
+ nav={"<h5>Folder: $RA{fullPath}</h5>"},
+ nowrap=true
)
)
- public FileListing listFiles(RestRequest req, @PathRemainder String
path) throws NotFound, Exception {
+ public FileResource getFile(RestRequest req, @PathRemainder String
path) throws NotFound, Exception {
- File dir = getDir(path);
+ File dir = getFile(path);
req.setAttribute("fullPath", dir.getAbsolutePath());
-
- FileListing l = new FileListing();
- for (File fc : dir.listFiles())
- l.add(new FileResource(fc, (path != null ? (path + '/')
: "") + urlEncode(fc.getName())));
- return l;
+
+ return new FileResource(dir, path, true);
}
@RestMethod(
- name=GET,
- path="/file/*",
- summary="View information about file",
- description="Returns detailed information about the specified
file.",
- htmldoc=@HtmlDoc(
- nav={"<h5>File: $RA{fullPath}</h5>"}
- )
+ name="VIEW",
+ path="/*",
+ summary="View contents of file",
+ description="View the contents of a file.\nContent-Type is set
to 'text/plain'."
)
- public FileResource getFileInfo(RestRequest req, @PathRemainder String
path) throws NotFound, Exception {
-
- File f = getFile(path);
- req.setAttribute("fullPath", f.getAbsolutePath());
-
- return new FileResource(f, path);
+ public FileContents viewFile(RestResponse res, @PathRemainder String
path) throws NotFound, MethodNotAllowed {
+ if (! allowViews)
+ throw new MethodNotAllowed("VIEW not enabled");
+
+ res.setContentType("text/plain");
+ try {
+ return new FileContents(getFile(path));
+ } catch (FileNotFoundException e) {
+ throw new NotFound("File not found");
+ }
+ }
+
+ @RestMethod(
+ name="DOWNLOAD",
+ path="/*",
+ summary="Download file",
+ description="Download the contents of a file.\nContent-Type is
set to 'application/octet-stream'."
+ )
+ public FileContents downloadFile(RestResponse res, @PathRemainder
String path) throws NotFound, MethodNotAllowed {
+ if (! allowViews)
+ throw new MethodNotAllowed("DOWNLOAD not enabled");
+
+ res.setContentType("application/octet-stream");
+ try {
+ return new FileContents(getFile(path));
+ } catch (FileNotFoundException e) {
+ throw new NotFound("File not found");
+ }
}
@RestMethod(
name=DELETE,
- path="/file/*",
+ path="/*",
summary="Delete file",
description="Delete a file on the file system."
)
public RedirectToRoot deleteFile(@PathRemainder String path) throws
MethodNotAllowed {
- if (! allowDeletes)
- throw new MethodNotAllowed("DELETE not enabled");
deleteFile(getFile(path));
return new RedirectToRoot();
}
@RestMethod(
name=PUT,
- path="/file/*",
+ path="/*",
summary="Add or replace file",
description="Add or overwrite a file on the file system."
)
@@ -171,7 +192,7 @@ public class DirectoryResource extends BasicRestServlet {
@PathRemainder String path
) throws InternalServerError {
- if (! allowPuts)
+ if (! allowUploads)
throw new MethodNotAllowed("PUT not enabled");
File f = getFile(path);
@@ -185,68 +206,12 @@ public class DirectoryResource extends BasicRestServlet {
return new RedirectToRoot();
}
- @RestMethod(
- name="VIEW",
- path="/file/*",
- summary="View contents of file",
- description="View the contents of a file."
- )
- public FileContents doView(RestResponse res, @PathRemainder String
path) throws NotFound, MethodNotAllowed {
- if (! allowViews)
- throw new MethodNotAllowed("VIEW not enabled");
-
- res.setContentType("text/plain");
- try {
- return new FileContents(getFile(path));
- } catch (FileNotFoundException e) {
- throw new NotFound("File not found");
- }
- }
-
- @RestMethod(
- name="DOWNLOAD",
- path="/file/*",
- summary="Download file",
- description="Download the contents of a file"
- )
- public FileContents doDownload(RestResponse res, @PathRemainder String
path) throws NotFound, MethodNotAllowed {
- if (! allowViews)
- throw new MethodNotAllowed("DOWNLOAD not enabled");
-
- res.setContentType("application/octet-stream");
- try {
- return new FileContents(getFile(path));
- } catch (FileNotFoundException e) {
- throw new NotFound("File not found");
- }
- }
-
- private File getFile(String path) throws NotFound {
- File f = new File(rootDir.getAbsolutePath() + '/' + path);
- if (f.exists() && f.isFile())
- return f;
- throw new NotFound("File not found.");
- }
-
- private File getDir(String path) throws NotFound {
- if (path == null)
- return rootDir;
- File f = new File(rootDir.getAbsolutePath() + '/' + path);
- if (f.exists() && f.isDirectory())
- return f;
- throw new NotFound("Directory not found.");
- }
-
//-----------------------------------------------------------------------------------------------------------------
// Helper beans
//-----------------------------------------------------------------------------------------------------------------
- @SuppressWarnings("serial")
- @ResponseInfo(description="Directory listing")
- static class FileListing extends ArrayList<FileResource> {}
-
@ResponseInfo(schema="{schema:{type:'string',format:'binary'}}",
description="Contents of file")
- static class FileContents extends FileReader {
+ static class FileContents extends FileInputStream {
public FileContents(File file) throws FileNotFoundException {
super(file);
}
@@ -263,31 +228,28 @@ public class DirectoryResource extends BasicRestServlet {
}
@ResponseInfo(description="File or directory details")
+ @Bean(properties="type,name,size,lastModified,actions,files")
public class FileResource {
- private File f;
- private String path;
+ private final File f;
+ private final String path;
+ private final String uri;
+ private final boolean includeChildren;
- public FileResource(File f, String path) {
+ public FileResource(File f, String path, boolean
includeChildren) {
this.f = f;
this.path = path;
- }
-
- // Bean property getters
-
- public URI getUri() {
- if (f.isDirectory())
- return URI.create("servlet:/"+path);
- return URI.create("servlet:/file/"+path);
+ this.uri = "servlet:/"+(path == null ? "" : path);
+ this.includeChildren = includeChildren;
}
public String getType() {
return (f.isDirectory() ? "dir" : "file");
}
- public String getName() {
- return f.getName();
+ public LinkString getName() {
+ return new LinkString(f.getName(), uri);
}
-
+
public long getSize() {
return f.isDirectory() ? f.listFiles().length :
f.length();
}
@@ -297,31 +259,70 @@ public class DirectoryResource extends BasicRestServlet {
return new Date(f.lastModified());
}
+ @Html(format=HtmlFormat.HTML_CDC)
public List<Action> getActions() throws Exception {
List<Action> l = new ArrayList<>();
if (allowViews && f.canRead() && ! f.isDirectory()) {
- l.add(new Action("view", getUri().toString() +
"?method=VIEW"));
- l.add(new Action("download",
getUri().toString() + "?method=DOWNLOAD"));
+ l.add(new Action("view", uri + "?method=VIEW"));
+ l.add(new Action("download", uri +
"?method=DOWNLOAD"));
}
if (allowDeletes && f.canWrite() && ! f.isDirectory())
- l.add(new Action("delete", getUri().toString()
+ "?method=DELETE"));
+ l.add(new Action("delete", uri +
"?method=DELETE"));
return l;
}
+
+ public Set<FileResource> getFiles() {
+ if (f.isFile() || ! includeChildren)
+ return null;
+ Set<FileResource> s = new TreeSet<>(new
FileResourceComparator());
+ for (File fc : f.listFiles())
+ s.add(new FileResource(fc, (path != null ?
(path + '/') : "") + urlEncode(fc.getName()), false));
+ return s;
+ }
+ }
+
+ static final class FileResourceComparator implements
Comparator<FileResource>, Serializable {
+ private static final long serialVersionUID = 1L;
+ @Override /* Comparator */
+ public int compare(FileResource o1, FileResource o2) {
+ int c = o1.getType().compareTo(o2.getType());
+ return c != 0 ? c :
o1.getName().compareTo(o2.getName());
+ }
+ }
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Helper methods
+
//-----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Returns the root directory.
+ *
+ * @return The root directory.
+ */
+ protected File getRootDir() {
+ return rootDir;
+ }
+
+ private File getFile(String path) throws NotFound {
+ if (path == null)
+ return rootDir;
+ File f = new File(rootDir.getAbsolutePath() + '/' + path);
+ if (f.exists())
+ return f;
+ throw new NotFound("File not found.");
}
- /** Utility method */
private void deleteFile(File f) {
- try {
- if (f.isDirectory()) {
- File[] files = f.listFiles();
- if (files != null) {
- for (File fc : files)
- deleteFile(fc);
- }
+ if (! allowDeletes)
+ throw new MethodNotAllowed("DELETE not enabled");
+ if (f.isDirectory()) {
+ File[] files = f.listFiles();
+ if (files != null) {
+ for (File fc : files)
+ deleteFile(fc);
}
- f.delete();
- } catch (Exception e) {
- logger.log(WARNING, "Cannot delete file '" +
f.getAbsolutePath() + "'", e);
}
+ if (! f.delete())
+ throw new Forbidden("Could not delete file {0}",
f.getAbsolutePath()) ;
}
}
diff --git
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
index 1446dfe..66751d0 100755
---
a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
+++
b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
@@ -12,19 +12,18 @@
//
***************************************************************************************************************************
package org.apache.juneau.microservice.resources;
-import static org.apache.juneau.html.HtmlDocSerializer.*;
+import static org.apache.juneau.html.HtmlSerializer.*;
import static org.apache.juneau.rest.annotation.HookEvent.*;
-import static org.apache.juneau.internal.StringUtils.*;
import static org.apache.juneau.http.HttpMethodName.*;
+import static org.apache.juneau.internal.StringUtils.*;
import java.io.*;
-import java.net.URI;
import java.nio.charset.*;
import java.util.*;
import org.apache.juneau.annotation.*;
-import org.apache.juneau.config.*;
-import org.apache.juneau.dto.LinkString;
+import org.apache.juneau.dto.*;
+import org.apache.juneau.html.annotation.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.converters.*;
@@ -41,6 +40,11 @@ import org.apache.juneau.transforms.*;
description="Log files from this service",
properties={
@Property(name=HTML_uriAnchorText, value="PROPERTY_NAME"),
+ @Property(name=LogsResource.LOGS_RESOURCE_logDir,
value="$C{Logging/logDir}"),
+ @Property(name=LogsResource.LOGS_RESOURCE_allowDeletes,
value="$C{Logging/allowDeletes,true}"),
+ @Property(name=LogsResource.LOGS_RESOURCE_logFormat,
value="$C{Logging/format}"),
+ @Property(name=LogsResource.LOGS_RESOURCE_dateFormat,
value="$C{Logging/dateFormat}"),
+ @Property(name=LogsResource.LOGS_RESOURCE_useStackTraceHashes,
value="$C{Logging/useStackTraceHashes}")
},
allowedMethodParams="*",
pojoSwaps={
@@ -48,119 +52,98 @@ import org.apache.juneau.transforms.*;
DateSwap.ISO8601DT.class // Serialize Date objects as ISO8601
strings.
}
)
+@SuppressWarnings("javadoc")
public class LogsResource extends BasicRestServlet {
private static final long serialVersionUID = 1L;
- private File logDir;
- private LogEntryFormatter leFormatter;
+
//-------------------------------------------------------------------------------------------------------------------
+ // Configurable properties
+
//-------------------------------------------------------------------------------------------------------------------
- private final FileFilter filter = new FileFilter() {
- @Override /* FileFilter */
- public boolean accept(File f) {
- return f.isDirectory() || f.getName().endsWith(".log");
- }
- };
+ private static final String PREFIX = "LogsResource.";
+
+ /**
+ * Configuration property: Root directory.
+ */
+ public static final String LOGS_RESOURCE_logDir = PREFIX + "logDir.s";
+
+ /**
+ * Configuration property: Allow deletes on files.
+ */
+ public static final String LOGS_RESOURCE_allowDeletes = PREFIX +
"allowDeletes.b";
+
+ /**
+ * Configuration property: Log entry format.
+ */
+ public static final String LOGS_RESOURCE_logFormat = PREFIX +
"logFormat.s";
/**
- * Initializes the log directory and formatter.
- *
- * @param builder The resource config.
- * @throws Exception
+ * Configuration property: Log entry format.
*/
- @RestHook(INIT)
- public void init(RestContextBuilder builder) throws Exception {
- Config c = builder.getConfig();
+ public static final String LOGS_RESOURCE_dateFormat = PREFIX +
"dateFormat.s";
- logDir = new File(c.getString("Logging/logDir", "."));
+ /**
+ * Configuration property: Log entry format.
+ */
+ public static final String LOGS_RESOURCE_useStackTraceHashes = PREFIX +
"useStackTraceHashes.b";
+
+
//-------------------------------------------------------------------------------------------------------------------
+ // Instance
+
//-------------------------------------------------------------------------------------------------------------------
+
+ private File logDir;
+ private LogEntryFormatter leFormatter;
+ boolean allowDeletes;
+
+
+ @RestHook(INIT)
+ public void init(RestContextBuilder b) throws Exception {
+ RestContextProperties p = b.getProperties();
+ logDir = new File(p.getString(LOGS_RESOURCE_logDir));
+ allowDeletes = p.getBoolean(LOGS_RESOURCE_allowDeletes);
leFormatter = new LogEntryFormatter(
- c.getString("Logging/format", "[{date} {level}]
{msg}%n"),
- c.getString("Logging/dateFormat", "yyyy.MM.dd
hh:mm:ss"),
- c.getBoolean("Logging/useStackTraceHashes")
+ p.getString(LOGS_RESOURCE_logFormat, "[{date} {level}]
{msg}%n"),
+ p.getString(LOGS_RESOURCE_dateFormat, "yyyy.MM.dd
hh:mm:ss"),
+ p.getBoolean(LOGS_RESOURCE_useStackTraceHashes, true)
);
}
- /**
- * [GET /*] - Get file details or directory listing.
- *
- * @param req The HTTP request
- * @param res The HTTP response
- * @param properties The writable properties for setting the
descriptions.
- * @param path The log file path.
- * @return The log file.
- * @throws Exception
- */
@RestMethod(
- name=GET,
+ name=GET,
path="/*",
- swagger= {
- "responses:{",
- "200: {description:'OK'},",
- "404: {description:'Not Found'}",
- "}"
- }
+ summary="View information on file or directory",
+ description="Returns information about the specified file or
directory.",
+ htmldoc=@HtmlDoc(
+ nav={"<h5>Folder: $RA{fullPath}</h5>"},
+ nowrap=true
+ )
)
- public Object getFileOrDirectory(RestRequest req, RestResponse res,
RequestProperties properties, @PathRemainder String path) throws Exception {
+ public FileResource getFile(RestRequest req, @PathRemainder String
path) throws NotFound, Exception {
- File f = getFile(path);
-
- if (f.isDirectory()) {
- Set<FileResource> l = new TreeSet<>(new
FileResourceComparator());
- File[] files = f.listFiles(filter);
- if (files != null) {
- for (File fc : files) {
- URI fUrl = new URI("servlet:/" +
fc.getName());
- l.add(new FileResource(fc, fUrl));
- }
- }
- return l;
- }
+ File dir = getFile(path);
+ req.setAttribute("fullPath", dir.getAbsolutePath());
- return new FileResource(f, new URI("servlet:/"));
+ return new FileResource(dir, path, allowDeletes, true);
}
- /**
- * [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 NotFound File not found.
- * @throws MethodNotAllowed View not available on directories.
- * @throws IOException Could not write file.
- */
@RestMethod(
name="VIEW",
path="/*",
- swagger= {
- "responses:{",
- "200: {description:'OK'},",
- "404: {description:'Not Found'}",
- "}"
- }
+ summary="View contents of log file",
+ description="View the contents of a log file."
)
public void viewFile(
- RestRequest req,
RestResponse res,
@PathRemainder String path,
- RequestProperties properties,
- @Query("highlight") boolean highlight,
- @Query("start") String start,
- @Query("end") String end,
- @Query("thread") String thread,
- @Query("loggers") String[] loggers,
- @Query("severity") String[] severity
+ @Query(name="highlight", description="Add severity
color highlighting.", example="true") boolean highlight,
+ @Query(name="start", description="Start timestamp
(ISO8601, full or partial).\nDon't print lines logged before the specified
timestamp.\nUse any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd,
yyyy-MM-ddThh, yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS",
example="2014-01-23T11:25:47") String start,
+ @Query(name="end", description="End timestamp (ISO8601,
full or partial).\nDon't print lines logged after the specified timestamp.\nUse
any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh,
yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS",
example="2014-01-24") String end,
+ @Query(name="thread", description="Thread name
filter.\nOnly show log entries with the specified thread name.",
example="thread-pool-33-thread-1") String thread,
+ @Query(name="loggers", description="Logger filter
(simple class name).\nOnly show log entries if they were produced by one of the
specified loggers.", example="['LinkIndexService','LinkIndexRestService']")
String[] loggers,
+ @Query(name="severity", description="Severity
filter.\nOnly show log entries with the specified severity.",
example="['ERROR','WARN']") String[] severity
) throws NotFound, MethodNotAllowed, IOException {
File f = getFile(path);
- if (f.isDirectory())
- throw new MethodNotAllowed("View not available on
directories");
Date startDate = parseISO8601Date(start), endDate =
parseISO8601Date(end);
@@ -203,168 +186,189 @@ public class LogsResource extends BasicRestServlet {
}
}
- /**
- * [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 NotFound File not found.
- * @throws MethodNotAllowed View not available on directories.
- * @throws IOException Could not read file.
- */
@RestMethod(
name="PARSE",
path="/*",
converters=Queryable.class,
- swagger= {
- "responses:{",
- "200: {description:'OK'},",
- "404: {description:'Not Found'}",
- "}"
+ summary="View parsed contents of file",
+ description="View the parsed contents of a file.",
+ htmldoc=@HtmlDoc(
+ nav={"<h5>Folder: $RA{fullPath}</h5>"}
+ ),
+ swagger={
+ "parameters:[",
+ Queryable.SWAGGER_PARAMS,
+ "]"
}
)
public LogParser viewParsedEntries(
- RestRequest req,
+ RestRequest req,
@PathRemainder String path,
- @Query("start") String start,
- @Query("end") String end,
- @Query("thread") String thread,
- @Query("loggers") String[] loggers,
- @Query("severity") String[] severity
- ) throws NotFound, MethodNotAllowed, IOException {
+ @Query(name="start", description="Start timestamp
(ISO8601, full or partial).\nDon't print lines logged before the specified
timestamp.\nUse any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd,
yyyy-MM-ddThh, yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS",
example="2014-01-23T11:25:47") String start,
+ @Query(name="end", description="End timestamp (ISO8601,
full or partial).\nDon't print lines logged after the specified timestamp.\nUse
any of the following formats: yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddThh,
yyyy-MM-ddThh:mm, yyyy-MM-ddThh:mm:ss, yyyy-MM-ddThh:mm:ss.SSS",
example="2014-01-24") String end,
+ @Query(name="thread", description="Thread name
filter.\nOnly show log entries with the specified thread name.",
example="thread-pool-33-thread-1") String thread,
+ @Query(name="loggers", description="Logger filter
(simple class name).\nOnly show log entries if they were produced by one of the
specified loggers.", example="['LinkIndexService','LinkIndexRestService']")
String[] loggers,
+ @Query(name="severity", description="Severity
filter.\nOnly show log entries with the specified severity.",
example="['ERROR','WARN']") String[] severity
+ ) throws NotFound, IOException {
File f = getFile(path);
- Date startDate = parseISO8601Date(start), endDate =
parseISO8601Date(end);
+ req.setAttribute("fullPath", f.getAbsolutePath());
- if (f.isDirectory())
- throw new MethodNotAllowed("View not available on
directories");
+ Date startDate = parseISO8601Date(start), endDate =
parseISO8601Date(end);
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 NotFound File not found.
- * @throws MethodNotAllowed Download not available on directories.
- */
@RestMethod(
- name="DOWNLOAD",
+ name="DOWNLOAD",
path="/*",
- swagger= {
- "responses:{",
- "200: {description:'OK'},",
- "404: {description:'Not Found'}",
- "}"
- }
+ summary="Download file",
+ description="Download the contents of a file.\nContent-Type is
set to 'application/octet-stream'."
)
- public Object downloadFile(RestResponse res, @PathRemainder String
path) throws NotFound, MethodNotAllowed {
-
- File f = getFile(path);
-
- if (f.isDirectory())
- throw new MethodNotAllowed("Download not available on
directories");
-
+ public FileContents downloadFile(RestResponse res, @PathRemainder
String path) throws NotFound, MethodNotAllowed {
res.setContentType("application/octet-stream");
- res.setContentLength((int)f.length());
-
try {
- return new FileInputStream(f);
+ return new FileContents(getFile(path));
} catch (FileNotFoundException e) {
throw new NotFound("File not found");
}
}
- /**
- * [DELETE /*] - Delete a file.
- *
- * @param path The log file path.
- * @return A redirect object to the root.
- * @throws NotFound File not found.
- * @throws BadRequest Delete not available on directories.
- * @throws Forbidden Could not delete file.
- */
@RestMethod(
- name=DELETE,
+ name=DELETE,
path="/*",
- swagger= {
- "responses:{",
- "200: {description:'OK'},",
- "404: {description:'Not Found'}",
- "}"
- }
+ summary="Delete log file",
+ description="Delete a log file on the file system."
)
- public Object deleteFile(@PathRemainder String path) throws NotFound,
BadRequest, Forbidden {
+ public RedirectToRoot deleteFile(@PathRemainder String path) throws
MethodNotAllowed {
+ deleteFile(getFile(path));
+ return new RedirectToRoot();
+ }
- File f = getFile(path);
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Helper beans
+
//-----------------------------------------------------------------------------------------------------------------
- if (f.isDirectory())
- throw new BadRequest("Delete not available on
directories.");
+ @ResponseInfo(schema="{schema:{type:'string',format:'binary'}}",
description="Contents of file")
+ static class FileContents extends FileInputStream {
+ public FileContents(File file) throws FileNotFoundException {
+ super(file);
+ }
+ }
+
+ @ResponseInfo(description="Redirect to root page on success")
+ static class RedirectToRoot extends RedirectToServletRoot {}
+
+ @ResponseInfo(description="File action")
+ public static class Action extends LinkString {
+ public Action(String name, String uri, Object...uriArgs) {
+ super(name, uri, uriArgs);
+ }
+ }
- if (f.canWrite())
- if (! f.delete())
- throw new Forbidden("Could not delete file.");
+ @ResponseInfo(description="File or directory details")
+ @Bean(properties="type,name,size,lastModified,actions,files")
+ public static class FileResource {
+ private final File f;
+ private final String path;
+ private final String uri;
+ private final boolean includeChildren, allowDeletes;
- return new Redirect(path + "/..");
- }
+ public FileResource(File f, String path, boolean allowDeletes,
boolean includeChildren) {
+ this.f = f;
+ this.path = path;
+ this.uri = "servlet:/"+(path == null ? "" : path);
+ this.includeChildren = includeChildren;
+ this.allowDeletes = allowDeletes;
+ }
- private static BufferedReader getReader(File f) throws IOException {
- return new BufferedReader(new InputStreamReader(new
FileInputStream(f), Charset.defaultCharset()));
+ public String getType() {
+ return (f.isDirectory() ? "dir" : "file");
+ }
+
+ public LinkString getName() {
+ return new LinkString(f.getName(), uri);
+ }
+
+ public long getSize() {
+ return f.isDirectory() ? f.listFiles().length :
f.length();
+ }
+
+ @Swap(DateSwap.ISO8601DTP.class)
+ public Date getLastModified() {
+ return new Date(f.lastModified());
+ }
+
+ @Html(format=HtmlFormat.HTML_CDC)
+ public List<Action> getActions() throws Exception {
+ List<Action> l = new ArrayList<>();
+ if (f.canRead() && ! f.isDirectory()) {
+ l.add(new Action("view", uri + "?method=VIEW"));
+ l.add(new Action("highlighted", uri +
"?method=VIEW&highlight=true"));
+ l.add(new Action("parsed", uri +
"?method=PARSE"));
+ l.add(new Action("download", uri +
"?method=DOWNLOAD"));
+ if (allowDeletes)
+ l.add(new Action("delete", uri +
"?method=DELETE"));
+ }
+ return l;
+ }
+
+ public Set<FileResource> getFiles() {
+ if (f.isFile() || ! includeChildren)
+ return null;
+ Set<FileResource> s = new TreeSet<>(FILE_COMPARATOR);
+ for (File fc : f.listFiles(FILE_FILTER))
+ s.add(new FileResource(fc, (path != null ?
(path + '/') : "") + urlEncode(fc.getName()), allowDeletes, false));
+ return s;
+ }
+
+ static final FileFilter FILE_FILTER = new FileFilter() {
+ @Override /* FileFilter */
+ public boolean accept(File f) {
+ return f.isDirectory() ||
f.getName().endsWith(".log");
+ }
+ };
+
+ static final Comparator<FileResource> FILE_COMPARATOR = new
Comparator<FileResource>() {
+ @Override /* Comparator */
+ public int compare(FileResource o1, FileResource o2) {
+ int c = o1.getType().compareTo(o2.getType());
+ return c != 0 ? c :
o1.getName().compareTo(o2.getName());
+ }
+ };
}
+
+
//-----------------------------------------------------------------------------------------------------------------
+ // Helper methods
+
//-----------------------------------------------------------------------------------------------------------------
+
private File getFile(String path) throws NotFound {
- if (path != null && path.indexOf("..") != -1)
- throw new NotFound("File not found.");
- File f = (path == null ? logDir : new
File(logDir.getAbsolutePath() + '/' + path));
- if (filter.accept(f))
+ if (path == null)
+ return logDir;
+ File f = new File(logDir.getAbsolutePath() + '/' + path);
+ if (f.exists())
return f;
throw new NotFound("File not found.");
}
-
- /**
- * File bean.
- */
- @SuppressWarnings("javadoc")
- public static class FileResource {
- final File f;
- public final String type;
- public final Object name;
- public final Long size;
- @Swap(DateSwap.DateTimeMedium.class) public Date lastModified;
- public URI view, highlighted, parsed, download, delete;
-
- public FileResource(File f, URI uri) throws Exception {
- this.f = f;
- this.type = (f.isDirectory() ? "dir" : "file");
- this.name = f.isDirectory() ? new
LinkString(f.getName(), uri.toString()) : f.getName();
- this.size = f.isDirectory() ? null : f.length();
- this.lastModified = new Date(f.lastModified());
- if (f.canRead() && ! f.isDirectory()) {
- this.view = new URI(uri + "?method=VIEW");
- this.highlighted = new URI(uri +
"?method=VIEW&highlight=true");
- this.parsed = new URI(uri + "?method=PARSE");
- this.download = new URI(uri +
"?method=DOWNLOAD");
- this.delete = new URI(uri + "?method=DELETE");
+
+ private void deleteFile(File f) {
+ if (! allowDeletes)
+ throw new MethodNotAllowed("DELETE not enabled");
+ if (f.isDirectory()) {
+ File[] files = f.listFiles();
+ if (files != null) {
+ for (File fc : files)
+ deleteFile(fc);
}
}
+ if (! f.delete())
+ throw new Forbidden("Could not delete file {0}",
f.getAbsolutePath()) ;
}
- static final 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 static BufferedReader getReader(File f) throws IOException {
+ return new BufferedReader(new InputStreamReader(new
FileInputStream(f), Charset.defaultCharset()));
}
private Object getReader(File f, final Date start, final Date end,
final String thread, final String[] loggers, final String[] severity) throws
IOException {
diff --git
a/juneau-microservice/juneau-microservice-template/my-microservice.cfg
b/juneau-microservice/juneau-microservice-template/my-microservice.cfg
index 10c9306..5fde384 100755
--- a/juneau-microservice/juneau-microservice-template/my-microservice.cfg
+++ b/juneau-microservice/juneau-microservice-template/my-microservice.cfg
@@ -94,12 +94,10 @@ logDir = logs
logFile = microservice.%g.log
# Whether to append to the existing log file or create a new one.
-# Default is false.
-append =
+append = false
# The SimpleDateFormat format to use for dates.
-# Default is "yyyy.MM.dd hh:mm:ss".
-dateFormat =
+dateFormat = yyyy.MM.dd hh:mm:ss
# The log message format.
# The value can contain any of the following variables:
@@ -111,17 +109,14 @@ dateFormat =
# {msg} - The log message.
# {threadid} - The thread ID.
# {exception} - The localized exception message.
-# Default is "[{date} {level}] {msg}%n".
-format =
+format = [{date} {level}] {msg}%n
# The maximum log file size.
# Suffixes available for numbers.
# See Config.getInt(String,int) for details.
-# Default is 1M.
-limit = 10M
+limit = 1M
# Max number of log files.
-# Default is 1.
count = 5
# Default log levels.
@@ -137,17 +132,14 @@ levels =
# Only print unique stack traces once and then refer to them by a simple 8
character hash identifier.
# Useful for preventing log files from filling up with duplicate stack traces.
-# Default is false.
useStackTraceHashes = true
# The default level for the console logger.
# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE,
FINER, FINEST)
-# Default is WARNING.
consoleLevel = WARNING
# The default level for the file logger.
# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE,
FINER, FINEST)
-# Default is INFO.
fileLevel = INFO
#=======================================================================================================================
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
index ae8d387..566f366 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
@@ -623,13 +623,13 @@ public class BasicRestInfoProvider implements
RestInfoProvider {
String paramName = piri.getString("name");
String s =
req.getPartSerializer().serialize(HttpPartType.valueOf(in.toUpperCase()),
example);
if ("query".equals(in))
- s = "?" + paramName + "=" + s;
+ s = "?" + urlEncodeLax(paramName) + "=" +
urlEncodeLax(s);
else if ("formData".equals(in))
s = paramName + "=" + s;
else if ("header".equals(in))
s = paramName + ": " + s;
else if ("path".equals(in))
- s =
sm.getPathPattern().replace("{"+paramName+"}", s);
+ s =
sm.getPathPattern().replace("{"+paramName+"}", urlEncodeLax(s));
examples.put("example", s);
}
--
To stop receiving notification emails like this one, please contact
[email protected].