diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java index f33de1fd781..217d7c10865 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java @@ -125,7 +125,11 @@ public abstract class BaseClient { } } - return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); + try { + return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); + } finally { + reader.close(); + } } catch (IllegalStateException e) { throw new FhirClientConnectionException(e); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClientInvocationWithContents.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClientInvocationWithContents.java index 60d8ea69334..4738720639f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClientInvocationWithContents.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClientInvocationWithContents.java @@ -69,7 +69,14 @@ public abstract class BaseClientInvocationWithContents extends BaseClientInvocat @Override public HttpRequestBase asHttpRequest(String theUrlBase) throws DataFormatException, IOException { - String url = theUrlBase + StringUtils.defaultString(myUrlExtension); + StringBuilder b = new StringBuilder(); + b.append(theUrlBase); + if (!theUrlBase.endsWith("/")) { + b.append('/'); + } + b.append(StringUtils.defaultString(myUrlExtension)); + + String url = b.toString(); String contents = myContext.newXmlParser().encodeResourceToString(myResource); StringEntity entity = new StringEntity(contents, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/DeleteClientInvocation.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/DeleteClientInvocation.java index e0de78b04df..f2ab453f51c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/DeleteClientInvocation.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/DeleteClientInvocation.java @@ -41,6 +41,9 @@ public class DeleteClientInvocation extends BaseClientInvocation { public HttpRequestBase asHttpRequest(String theUrlBase) throws DataFormatException, IOException { StringBuilder b = new StringBuilder(); b.append(theUrlBase); + if (!theUrlBase.endsWith("/")) { + b.append('/'); + } b.append(myUrlPath); HttpDelete retVal = new HttpDelete(b.toString()); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java index 85837457736..48a25be4079 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -22,18 +22,24 @@ package ca.uhn.fhir.rest.client; import java.io.IOException; import java.io.Reader; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpRequestBase; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.rest.method.IClientResponseHandler; import ca.uhn.fhir.rest.method.ReadMethodBinding; +import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.server.EncodingUtil; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; @@ -109,4 +115,36 @@ public class GenericClient extends BaseClient implements IGenericClient { T resp = (T) invokeClient(binding, invocation); return resp; } + + + @Override + public Bundle search(final Class theType, Map> theParams) { + LinkedHashMap> params = new LinkedHashMap>(); + for (Entry> nextEntry : theParams.entrySet()) { + ArrayList valueList = new ArrayList(); + params.put(nextEntry.getKey(), valueList); + for (IQueryParameterType nextValue : nextEntry.getValue()) { + valueList.add(nextValue.getValueAsQueryToken()); + } + } + + GetClientInvocation invocation = SearchMethodBinding.createSearchInvocation(toResourceName(theType), params); + if (isKeepResponses()) { + myLastRequest = invocation.asHttpRequest(getServerBase()); + } + + IClientResponseHandler binding = new IClientResponseHandler() { + @Override + public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, + BaseServerResponseException { + EncodingUtil respType = EncodingUtil.forContentType(theResponseMimeType); + IParser parser = respType.newParser(myContext); + return parser.parseBundle(theType, theResponseReader); + } + }; + + Bundle resp = (Bundle) invokeClient(binding, invocation); + return resp; + } + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GetClientInvocation.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GetClientInvocation.java index fa5bca1fe45..dd321c0ea8c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GetClientInvocation.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GetClientInvocation.java @@ -66,6 +66,9 @@ public class GetClientInvocation extends BaseClientInvocation { public HttpRequestBase asHttpRequest(String theUrlBase) { StringBuilder b = new StringBuilder(); b.append(theUrlBase); + if (!theUrlBase.endsWith("/")) { + b.append('/'); + } b.append(myUrlPath); boolean first = true; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java index 35ed398657d..df7bbdedc56 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/IGenericClient.java @@ -20,13 +20,18 @@ package ca.uhn.fhir.rest.client; * #L% */ +import java.util.List; +import java.util.Map; + +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.primitive.IdDt; public interface IGenericClient { /** - * Implementation of the "read" method. + * Implementation of the "instance read" method. * * @param theType The type of resource to load * @param theId The ID to load @@ -35,7 +40,7 @@ public interface IGenericClient { T read(Class theType, IdDt theId); /** - * Implementation of the "vread" method. + * Implementation of the "instance vread" method. * * @param theType The type of resource to load * @param theId The ID to load @@ -44,4 +49,12 @@ public interface IGenericClient { */ T vread(Class theType, IdDt theId, IdDt theVersionId); + /** + * Implementation of the "instance search" method. + * @param theType The type of resource to load + * @param theParams + * @return + */ + Bundle search(Class theType, Map> theParams); + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java index 84a4ec56e37..c64efe022c3 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/SearchMethodBinding.java @@ -92,7 +92,12 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding { } } - return new GetClientInvocation(queryStringArgs, getResourceName()); + String resourceName = getResourceName(); + return createSearchInvocation(resourceName, queryStringArgs); + } + + public static GetClientInvocation createSearchInvocation(String theResourceName, Map> theParameters) { + return new GetClientInvocation(theParameters, theResourceName); } @Override diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java index 22785243013..0e78233152c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/ParameterUtil.java @@ -20,6 +20,8 @@ package ca.uhn.fhir.rest.param; * #L% */ +import static org.apache.commons.lang3.StringUtils.*; + import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; @@ -40,6 +42,7 @@ import org.apache.commons.lang3.time.DateUtils; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.PathSpecification; +import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.IntegerDt; import ca.uhn.fhir.rest.annotation.Count; @@ -93,12 +96,14 @@ public class ParameterUtil { parameter.setName(((RequiredParam) nextAnnotation).name()); parameter.setRequired(true); parameter.setType(parameterType, innerCollectionType, outerCollectionType); + extractDescription(parameter, annotations); param = parameter; } else if (nextAnnotation instanceof OptionalParam) { SearchParameter parameter = new SearchParameter(); parameter.setName(((OptionalParam) nextAnnotation).name()); parameter.setRequired(false); parameter.setType(parameterType, innerCollectionType, outerCollectionType); + extractDescription(parameter, annotations); param = parameter; } else if (nextAnnotation instanceof IncludeParam) { if (parameterType != PathSpecification.class || innerCollectionType == null || outerCollectionType != null) { @@ -141,6 +146,19 @@ public class ParameterUtil { return parameters; } + private static void extractDescription(SearchParameter theParameter, Annotation[] theAnnotations) { + for (Annotation annotation : theAnnotations) { + if (annotation instanceof Description) { + Description desc = (Description) annotation; + if (isNotBlank(desc.formalDefinition())) { + theParameter.setDescription(desc.formalDefinition()); + } else { + theParameter.setDescription(desc.shortDefinition()); + } + } + } + } + public static InstantDt toInstant(Object theArgument) { if (theArgument instanceof InstantDt) { return (InstantDt) theArgument; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/SearchParameter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/SearchParameter.java index 71348cfdf26..14091551b83 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/SearchParameter.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/SearchParameter.java @@ -38,18 +38,19 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; */ public class SearchParameter extends BaseQueryParameter { - private String name; + private String myDescription; + private String myName; private IParamBinder myParamBinder; - private boolean required; - private Class type; private SearchParamTypeEnum myParamType; + private boolean myRequired; + private Class myType; public SearchParameter() { } public SearchParameter(String name, boolean required) { - this.name = name; - this.required = required; + this.myName = name; + this.myRequired = required; } /* (non-Javadoc) @@ -60,21 +61,35 @@ public class SearchParameter extends BaseQueryParameter { return myParamBinder.encode(theObject); } + public String getDescription() { + return myDescription; + } + /* (non-Javadoc) * @see ca.uhn.fhir.rest.param.IParameter#getName() */ @Override public String getName() { - return name; + return myName; + } + + @Override + public SearchParamTypeEnum getParamType() { + return myParamType; } public Class getType() { - return type; + return myType; + } + + @Override + public boolean handlesMissing() { + return false; } @Override public boolean isRequired() { - return required; + return myRequired; } /* (non-Javadoc) @@ -85,17 +100,21 @@ public class SearchParameter extends BaseQueryParameter { return myParamBinder.parse(theString); } + public void setDescription(String theDescription) { + myDescription = theDescription; + } + public void setName(String name) { - this.name = name; + this.myName = name; } public void setRequired(boolean required) { - this.required = required; + this.myRequired = required; } @SuppressWarnings("unchecked") public void setType(final Class type, Class> theInnerCollectionType, Class> theOuterCollectionType) { - this.type = type; + this.myType = type; if (IQueryParameterType.class.isAssignableFrom(type)) { this.myParamBinder = new QueryParameterTypeBinder((Class) type); } else if (IQueryParameterOr.class.isAssignableFrom(type)) { @@ -132,14 +151,4 @@ public class SearchParameter extends BaseQueryParameter { } - @Override - public SearchParamTypeEnum getParamType() { - return myParamType; - } - - @Override - public boolean handlesMissing() { - return false; - } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java index 397a1aeea46..41c1f952c17 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java @@ -44,6 +44,7 @@ import ca.uhn.fhir.rest.method.ReadMethodBinding; import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.param.IParameter; import ca.uhn.fhir.rest.param.BaseQueryParameter; +import ca.uhn.fhir.rest.param.SearchParameter; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; @@ -110,19 +111,18 @@ public class ServerConformanceProvider { RestResourceSearchParam searchParam = null; StringDt searchParamChain = null; for (IParameter nextParameterObj : params) { - if (!(nextParameterObj instanceof BaseQueryParameter)) { + if (!(nextParameterObj instanceof SearchParameter)) { continue; } - BaseQueryParameter nextParameter = (BaseQueryParameter)nextParameterObj; - if (nextParameter.getName().startsWith("_")) { - continue; - } + SearchParameter nextParameter = (SearchParameter)nextParameterObj; if (searchParam == null) { if (!nameToSearchParam.containsKey(nextParameter.getName())) { RestResourceSearchParam param = resource.addSearchParam(); param.setName(nextParameter.getName()); + param.setDocumentation(nextParameter.getDescription()); + param.setType(nextParameter.getParamType()); searchParam = param; } else { searchParam = nameToSearchParam.get(nextParameter.getName()); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java index 112226cd48a..8b3357237ce 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java @@ -22,7 +22,11 @@ package ca.uhn.fhir.rest.server.tester; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -44,14 +48,17 @@ import org.thymeleaf.templateresolver.TemplateResolver; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.dstu.resource.Conformance; import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.rest.annotation.Metadata; import ca.uhn.fhir.rest.client.GenericClient; import ca.uhn.fhir.rest.client.IGenericClient; import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.EncodingUtil; +import ca.uhn.fhir.testmodel.IdentifierDt; public class PublicTesterServlet extends HttpServlet { @@ -74,23 +81,22 @@ public class PublicTesterServlet extends HttpServlet { myStaticResources.put("PublicTester.css", "text/css"); myStaticResources.put("hapi_fhir_banner.png", "image/png"); myStaticResources.put("hapi_fhir_banner_right.png", "image/png"); - myStaticResources.put("shCore.js","text/javascript"); - myStaticResources.put("shBrushJScript.js" ,"text/javascript"); - myStaticResources.put("shBrushXml.js" ,"text/javascript"); - myStaticResources.put("shBrushPlain.js" ,"text/javascript"); + myStaticResources.put("shCore.js", "text/javascript"); + myStaticResources.put("shBrushJScript.js", "text/javascript"); + myStaticResources.put("shBrushXml.js", "text/javascript"); + myStaticResources.put("shBrushPlain.js", "text/javascript"); myStaticResources.put("shCore.css", "text/css"); myStaticResources.put("shThemeDefault.css", "text/css"); - myCtx = new FhirContext(); } @Override protected void doPost(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException { if (DEBUGMODE) { - myTemplateEngine.getCacheManager().clearAllCaches(); + myTemplateEngine.getCacheManager().clearAllCaches(); } - + try { GenericClient client = (GenericClient) myCtx.newRestfulGenericClient(myServerBase); client.setKeepResponses(true); @@ -103,25 +109,16 @@ public class PublicTesterServlet extends HttpServlet { String resultSyntaxHighlighterClass; if ("read".equals(method)) { - String resourceName = StringUtils.defaultString(theReq.getParameter("resourceName")); - RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName); - if (def == null) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid resourceName: " + resourceName); - return; - } + RuntimeResourceDefinition def = getResourceType(theReq); String id = StringUtils.defaultString(theReq.getParameter("id")); if (StringUtils.isBlank(id)) { theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); } client.read(def.getImplementingClass(), new IdDt(id)); - } if ("vread".equals(method)) { - String resourceName = StringUtils.defaultString(theReq.getParameter("resourceName")); - RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName); - if (def == null) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid resourceName: " + resourceName); - return; - } + } + if ("vread".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); String id = StringUtils.defaultString(theReq.getParameter("id")); if (StringUtils.isBlank(id)) { theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); @@ -133,7 +130,48 @@ public class PublicTesterServlet extends HttpServlet { } client.vread(def.getImplementingClass(), new IdDt(id), new IdDt(versionId)); + } else if ("searchType".equals(method)) { + + Map> params = new HashMap>(); + + HashSet hashSet = new HashSet(theReq.getParameterMap().keySet()); + String paramName = null; + IQueryParameterType paramValue = null; + while (hashSet.isEmpty() == false) { + + String nextKey = hashSet.iterator().next(); + String nextValue = theReq.getParameter(nextKey); + paramName=null; + paramValue=null; + + if (nextKey.startsWith("param.token.")) { + int prefixLength = "param.token.".length(); + paramName = nextKey.substring(prefixLength + 2); + String systemKey = "param.token."+"1." + paramName; + String valueKey = "param.token."+"2." + paramName; + String system = theReq.getParameter(systemKey); + String value = theReq.getParameter(valueKey); + paramValue = new IdentifierDt(system, value); + hashSet.remove(systemKey); + hashSet.remove(valueKey); + } else if (nextKey.startsWith("param.string.")) { + paramName = nextKey.substring("param.string.".length()); + paramValue = new StringDt(nextValue); + } + + if (paramName != null) { + if (params.containsKey(paramName) == false) { + params.put(paramName, new ArrayList()); + } + params.get(paramName).add(paramValue); + } + + hashSet.remove(nextKey); + } + RuntimeResourceDefinition def = getResourceType(theReq); + client.search(def.getImplementingClass(), params); + } else { theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid method: " + method); return; @@ -150,13 +188,13 @@ public class PublicTesterServlet extends HttpServlet { EncodingUtil ctEnum = EncodingUtil.forContentType(mimeType); switch (ctEnum) { case JSON: - resultSyntaxHighlighterClass="brush: jscript"; + resultSyntaxHighlighterClass = "brush: jscript"; break; case XML: - resultSyntaxHighlighterClass="brush: xml"; + resultSyntaxHighlighterClass = "brush: xml"; break; default: - resultSyntaxHighlighterClass="brush: plain"; + resultSyntaxHighlighterClass = "brush: plain"; break; } @@ -167,7 +205,7 @@ public class PublicTesterServlet extends HttpServlet { ctx.setVariable("resultStatus", resultStatus); ctx.setVariable("resultBody", StringEscapeUtils.escapeHtml4(resultBody)); ctx.setVariable("resultSyntaxHighlighterClass", resultSyntaxHighlighterClass); - + myTemplateEngine.process(PUBLIC_TESTER_RESULT_HTML, ctx, theResp.getWriter()); } catch (Exception e) { ourLog.error("Failure during processing", e); @@ -175,12 +213,21 @@ public class PublicTesterServlet extends HttpServlet { } } + private RuntimeResourceDefinition getResourceType(HttpServletRequest theReq) throws ServletException { + String resourceName = StringUtils.defaultString(theReq.getParameter("resourceName")); + RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName); + if (def == null) { + throw new ServletException("Invalid resourceName: " + resourceName); + } + return def; + } + @Override protected void doGet(HttpServletRequest theReq, HttpServletResponse theResp) throws ServletException, IOException { if (DEBUGMODE) { - myTemplateEngine.getCacheManager().clearAllCaches(); + myTemplateEngine.getCacheManager().clearAllCaches(); } - + ourLog.info("RequestURI: {}", theReq.getPathInfo()); String resName = theReq.getPathInfo().substring(1); diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js index f2f77740c7d..66353f65481 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/rest/server/tester/PublicTester.js @@ -46,11 +46,24 @@ function displaySearchType(expandoTr, resourceName) { $('', { name: 'method', value: 'searchType', type: 'hidden' }), $('', { name: 'resourceName', value: resourceName, type: 'hidden' }) ) + if (searchParam.documentation && searchParam.documentation.length > 0) { + formElement.append( + $('' + searchParam.documentation + '
') + ); + } var inputId = newUniqueId(); - formElement.append( - $('', { name: 'param.' + searchParam.name, placeholder: searchParam.name, type: 'text', id: inputId }), - $('