/**
* 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.apispark.internal.introspection.application;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.restlet.Application;
import org.restlet.Component;
import org.restlet.data.Protocol;
import org.restlet.data.Reference;
import org.restlet.engine.util.StringUtils;
import org.restlet.ext.apispark.internal.introspection.DocumentedApplication;
import org.restlet.ext.apispark.internal.introspection.IntrospectionHelper;
import org.restlet.ext.apispark.internal.model.Contract;
import org.restlet.ext.apispark.internal.model.Definition;
import org.restlet.ext.apispark.internal.model.Endpoint;
import org.restlet.ext.apispark.internal.reflect.ReflectUtils;
import org.restlet.ext.apispark.internal.utils.IntrospectionUtils;
import org.restlet.routing.VirtualHost;
/**
* Publish the documentation of a Restlet-based Application to the APISpark
* console.
*
* @author Thierry Boileau
*/
public class ApplicationIntrospector extends IntrospectionUtils {
/** Internal logger. */
protected static Logger LOGGER = Logger
.getLogger(ApplicationIntrospector.class.getName());
private static void addEnpoints(Application application, Reference baseRef,
Component component, Definition definition, Contract contract,
CollectInfo collectInfo) {
String scheme = collectInfo.getSchemes().isEmpty() ? null : collectInfo
.getSchemes().get(0).getName();
// Introspect component if any
if (baseRef != null) {
Endpoint endpoint = new Endpoint(baseRef.getHostDomain(),
baseRef.getHostPort(), baseRef.getSchemeProtocol()
.getSchemeName(), baseRef.getPath(), scheme);
definition.getEndpoints().add(endpoint);
}
if (component != null) {
LOGGER.fine("Look for the endpoint.");
// Look for the endpoint to which this application is attached.
Endpoint endpoint = ComponentIntrospector.getEndpoint(
component.getDefaultHost(), application, scheme);
if (endpoint != null) {
definition.getEndpoints().add(endpoint);
}
for (VirtualHost virtualHost : component.getHosts()) {
endpoint = ComponentIntrospector.getEndpoint(virtualHost,
application, scheme);
if (endpoint != null) {
definition.getEndpoints().add(endpoint);
}
}
}
// if no endpoints are defined, add a default one to have correct scheme
if (definition.getEndpoints().isEmpty()) {
Endpoint endpoint = new Endpoint("example.com", 80,
Protocol.HTTP.getSchemeName(), "/v1", scheme);
definition.getEndpoints().add(endpoint);
}
}
/**
* Returns an instance of what must be a subclass of
* {@link org.restlet.Application}. Returns null in case of errors.
*
* @param className
* The name of the application class.
* @return An instance of what must be a subclass of
* {@link org.restlet.Application}.
*/
public static Application getApplication(String className) {
return ReflectUtils.newInstance(className, Application.class);
}
/**
* Constructor.
*
* @param application
* An application to introspect.
*/
public static Definition getDefinition(Application application) {
return getDefinition(application, null, null, false);
}
/**
* Returns a APISpark description of the current application. By default,
* this method discovers all the resources attached to this application. It
* can be overridden to add documentation, list of representations, etc.
*
* @param application
* An application to introspect.
* @param component
* An component to introspect in order to get extra details such
* as the endpoint.
*
* @return An application description.
*/
public static Definition getDefinition(Application application,
Reference baseRef, Component component, boolean useSectionNamingPackageStrategy) {
List<IntrospectionHelper> introspectionHelpers = IntrospectionUtils.getIntrospectionHelpers();
// initialize the list to avoid to add a null check statement
if (introspectionHelpers == null) {
introspectionHelpers = new ArrayList<>();
}
Definition definition = new Definition();
// Contract
Contract contract = new Contract();
contract.setDescription(StringUtils.nullToEmpty(application
.getDescription()));
if (StringUtils.isNullOrEmpty(application.getName())) {
LOGGER.log(Level.WARNING,
"Please provide a name to your application, used "
+ contract.getName() + " by default.");
contract.setName(application.getClass().getName());
} else {
contract.setName(application.getName());
}
// Sections
CollectInfo collectInfo = new CollectInfo();
collectInfo.setUseSectionNamingPackageStrategy(useSectionNamingPackageStrategy);
if (application instanceof DocumentedApplication) {
DocumentedApplication documentedApplication = (DocumentedApplication) application;
if (documentedApplication.getSections() != null) {
collectInfo.setSections(documentedApplication.getSections());
}
}
definition.setContract(contract);
// Go through restlet nodes to collect resources, representations and
// schemes
RestletCollector.collect(collectInfo /*
* resources are added during
* collect
*/, "" /* start path is empty */,
application.getInboundRoot(), null /*
* there is no challenge
* scheme yet
*/, introspectionHelpers);
// add resources
contract.setResources(collectInfo.getResources());
// add representations
contract.setRepresentations(collectInfo.getRepresentations());
// add sections
contract.setSections(collectInfo.getSections());
addEnpoints(application, baseRef, component, definition, contract,
collectInfo);
sortDefinition(definition);
updateRepresentationsSectionsFromResources(definition);
for (IntrospectionHelper helper : introspectionHelpers) {
helper.processDefinition(definition, application.getClass());
}
return definition;
}
}