/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.ext.raml;
import org.raml.emitter.RamlEmitter;
import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.ext.apispark.internal.conversion.raml.RamlTranslator;
import org.restlet.ext.apispark.internal.introspection.application.ApplicationIntrospector;
import org.restlet.ext.apispark.internal.model.Definition;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.routing.Router;
/**
* Restlet that generates RAML documentation in the format defined by the RAML
* specifications.<br>
* It helps to generate the documentation for the whole API (set by calling
* {@link #setApiInboundRoot(Application)} or
* {@link #setApiInboundRoot(Restlet)} methods.<br>
* By default it instrospects the chain of Application's routers, filters,
* restlets.<br>
*
* <p>
* Usage example:
*
* <pre>
* RamlSpecificationRestlet ramlSpecificationRestlet = new RamlSpecificationRestlet();
* ramlSpecificationRestlet.setApiInboundRoot(this);
* ramlSpecificationRestlet.setBasePath("http://myapp.com/api/v1");
* ramlSpecificationRestlet.attach(baseRouter);
* </pre>
*
* </p>
*
* @author Cyprien Quilici
* @link http://raml.org/
* @link http://raml.org/spec.html
*/
public class RamlSpecificationRestlet extends Restlet {
/** The root Restlet to describe. */
private Restlet apiInboundRoot;
/** The version of the API. */
private String apiVersion;
/** The Application to describe. */
private Application application;
/** The base path of the API. */
private String basePath;
/** The base reference of the API. */
private Reference baseRef;
/** The definition of the API. */
private Definition definition;
/** The version of the supported RAML specifications. */
private String ramlVersion;
/**
* Default constructor.<br>
*/
public RamlSpecificationRestlet() {
this(null);
}
/**
* Constructor.<br>
*
* @param context
* The context.
*/
public RamlSpecificationRestlet(Context context) {
super(context);
ramlVersion = "0.8";
}
/**
* Defines one route (by default "/raml") for serving the application
* specification.
*
* @param router
* The router on which defining the new route.
*
* @see #attach(org.restlet.routing.Router, String) to attach it with a
* custom path
*/
public void attach(Router router) {
attach(router, "/raml");
}
/**
* Defines one route (by default "/raml") for serving the application
* specification.
*
* @param router
* The router on which defining the new route.
* @param path
* The root path of the documentation Restlet.
*
* @see #attach(org.restlet.routing.Router) to attach it with the default
* path
*/
public void attach(Router router, String path) {
router.attach(path, this);
}
/**
* Returns the root Restlet for the given application.
*
* @return The root Restlet for the given application.
*/
public Restlet getApiInboundRoot() {
if (apiInboundRoot == null) {
if (application != null) {
apiInboundRoot = application.getInboundRoot();
}
}
return apiInboundRoot;
}
/**
* Returns the API's version.
*
* @return The API's version.
*/
public String getApiVersion() {
return apiVersion;
}
/**
* Returns the base path of the API.
*
* @return The base path of the API.
*/
public String getBasePath() {
return basePath;
}
/**
* Returns the application's definition.
*
* @return The application's definition.
*/
private synchronized Definition getDefinition() {
if (definition == null) {
synchronized (RamlSpecificationRestlet.class) {
definition = ApplicationIntrospector.getDefinition(application,
baseRef, null, false);
if (definition.getVersion() == null) {
definition.setVersion("1.0");
}
}
}
return definition;
}
/**
* Returns the representation of the whole resource listing of the
* Application.
*
* @return The representation of the whole resource listing of the
* Application.
*/
public Representation getRaml() {
return new StringRepresentation(new RamlEmitter().dump(RamlTranslator
.getRaml(getDefinition())), MediaType.TEXT_PLAIN);
}
/**
* Returns the version of RAML used to generate this documentation.
*
* @return The version of RAML used to generate this documentation.
*/
public String getRamlVersion() {
return ramlVersion;
}
@Override
public void handle(Request request, Response response) {
if (Method.GET.equals(request.getMethod())) {
response.setEntity(getRaml());
} else {
response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED);
}
}
/**
* Sets the root Restlet for the given application.
*
* @param application
* The application.
*/
public void setApiInboundRoot(Application application) {
this.application = application;
}
/**
* Sets the root Restlet for the given application.
*
* @param apiInboundRoot
* The application's root Restlet.
*/
public void setApiInboundRoot(Restlet apiInboundRoot) {
this.apiInboundRoot = apiInboundRoot;
}
/**
* Sets the API's version.
*
* @param apiVersion
* The API version.
*/
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
/**
* Sets the base path of the API.
*
* @param basePath
* The base path of the API
*/
public void setBasePath(String basePath) {
this.basePath = basePath;
// Process basepath and check validity
this.baseRef = basePath != null ? new Reference(basePath) : null;
}
/**
* Sets the version of RAML used to generate this documentation.
*
* @param ramlVersion
* The version of RAML.
*/
public void setRamlVersion(String ramlVersion) {
this.ramlVersion = ramlVersion;
}
}