/**
* Licensed to The Apereo Foundation under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
*
* The Apereo Foundation licenses this file to you under the Educational
* Community 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://opensource.org/licenses/ecl2.txt
*
* 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.opencastproject.runtimeinfo.rest;
import org.opencastproject.util.doc.DocData;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* This is the document model class which holds the data about a set of rest endpoints, build this one time and reuse it
* whenever you need to generate rest documentation
*/
@Deprecated
public class DocRestData extends DocData {
public static final String FORMAT_KEY = "{FORMAT}";
public static final String SLASH = "/";
protected List<RestEndpointHolder> holders;
/**
* Create the base data object for creating REST documents
*
* @param name
* the name of the set of rest enpoints (must be alphanumeric (includes _) and no spaces or special chars)
* @param title
* [OPTIONAL] the title of the document
* @param url
* this is the absolute base URL for this endpoint, do not include the trailing slash (e.g. /workflow)
* @param notes
* [OPTIONAL] an array of notes to add into the end of the doc
*/
public DocRestData(String name, String title, String url, String[] notes) {
super(name, title, notes);
if (url == null || "".equals(url)) {
throw new IllegalArgumentException("url cannot be blank");
}
this.meta.put("url", url);
// create the endpoint holders
this.holders = new Vector<RestEndpointHolder>(2);
this.holders.add(new RestEndpointHolder(RestEndpoint.Type.READ.name(), "Read"));
this.holders.add(new RestEndpointHolder(RestEndpoint.Type.WRITE.name(), "Write"));
}
@Override
public Map<String, Object> toMap() {
LinkedHashMap<String, Object> m = new LinkedHashMap<String, Object>();
m.put("meta", this.meta);
m.put("notes", this.notes);
// only pass through the holders with things in them
ArrayList<RestEndpointHolder> holdersList = new ArrayList<RestEndpointHolder>();
for (RestEndpointHolder holder : this.holders) {
if (!holder.getEndpoints().isEmpty()) {
for (RestEndpoint endpoint : holder.getEndpoints()) {
// validate the endpoint
if (!endpoint.getPathParams().isEmpty()) {
for (Param param : endpoint.getPathParams()) {
if (!endpoint.getPath().contains("{" + param.getName() + "}")) {
throw new IllegalArgumentException("Path (" + endpoint.getPath() + ") does not match path parameter ("
+ param.getName() + ") for endpoint (" + endpoint.getName()
+ "), the path must contain all path param names");
}
}
}
// validate the path in the endpoint
Pattern pattern = Pattern.compile("\\{(.+?)\\}");
Matcher matcher = pattern.matcher(endpoint.getPath());
int count = 0;
while (matcher.find()) {
if (!FORMAT_KEY.equals(matcher.group())) {
count++;
}
}
if (count != endpoint.getPathParams().size()) {
throw new IllegalArgumentException("Path (" + endpoint.getPath() + ") does not match path parameters ("
+ endpoint.getPathParams() + ") for endpoint (" + endpoint.getName()
+ "), the path must contain the same number of path params (" + count
+ ") as the pathParams list (" + endpoint.getPathParams().size() + ")");
}
// handle the forms
if (endpoint.getForm() != null) {
RestTestForm form = endpoint.getForm();
if (form.isAutoGenerated()) {
// autogenerate the test form
form = new RestTestForm(endpoint);
endpoint.setTestForm(form); // replace
}
if (form.isEmpty()) {
// clear the form if there is no data to test
endpoint.setTestForm(null);
}
}
// handle the endpoint auto format paths
if (endpoint.isAutoPathFormat()) {
if (!endpoint.getFormats().isEmpty()) {
endpoint.setPathFormat("." + FORMAT_KEY);
StringBuilder sb = new StringBuilder();
sb.append(".{");
for (Format format : endpoint.getFormats()) {
if (sb.length() > 3) {
sb.append("|");
}
sb.append(format.getName());
}
sb.append("}");
endpoint.setPathFormatHtml(sb.toString());
}
} else {
endpoint.setPathFormat("");
endpoint.setPathFormatHtml("");
}
}
holdersList.add(holder);
}
}
m.put("endpointHolders", holdersList);
return m;
}
@Override
public String getDefaultTemplatePath() {
return TEMPLATE_DEFAULT;
}
@Override
public String toString() {
return "DOC:meta=" + meta + ", notes=" + notes + ", " + holders;
}
public void addEndpoint(RestEndpoint.Type type, RestEndpoint endpoint) {
if (type == null || endpoint == null) {
throw new IllegalArgumentException("type and endpoint must not be null");
}
RestEndpointHolder currentHolder = null;
for (RestEndpointHolder holder : this.holders) {
if (type.name().equals(holder.getName())) {
currentHolder = holder;
break;
}
}
if (currentHolder == null) {
throw new IllegalStateException("Could not find holder of type: " + type.name());
}
currentHolder.addEndPoint(endpoint);
}
/**
* Creates an abstract section which is displayed at the top of the doc
*
* @param abstractText
* any text to place at the top of the document, can be html markup but must be valid
*/
public void setAbstract(String abstractText) {
if (isBlank(abstractText)) {
this.meta.remove("abstract");
} else {
this.meta.put("abstract", abstractText);
}
}
/**
* Validates paths: VALID: /sample , /sample/{thing} , /{my}/{path}.xml , /my/fancy_path/is/{awesome}.{FORMAT}
* INVALID: sample, /sample/, /sa#$%mple/path
*
* @param path
* the path value to check
* @return true if this path is valid, false otherwise
*/
public static boolean isValidPath(String path) {
boolean valid = true;
if (isBlank(path)) {
valid = false;
} else {
if (SLASH.equals(path)) {
valid = true;
} else if (path.endsWith("/") || !path.startsWith("/")) {
valid = false;
} else {
if (!path.matches("^[\\w\\/{}\\.]+$")) {
valid = false;
}
}
}
return valid;
}
}