WebContent plugins are plugins that exist to serve various types of content over HTTP. To make a plugin a WebContent plugin, add ‘WebContent=<type>’ to the plugin’s .cfg file, where <type> is one of the types below:
- Static – serves up static files.
- Dynamic/ReSTful – serves up content provided by Java or Python code
The URL(s) that your plugin responds to are determined by the URIPatterns attribute. If it is missing, a default is chosen. This is a comma-separated list of relative URIs for your plugin. In addition, all web-content plugins are made available at a special URI that starts with /plugin_eval: for example, a plugin named foo.bar would be made available at /plugin_eval/foo/bar. This simplifies the client code, which can map a plugin name to a URL without having to look up the mapping for that URL from the server. Although this URL can be used externally, it is not recommended, because it is tied directly to the name of the plugin and offers less abstraction.
When a URL comes in, all URIPatterns that are a prefix to the URL are matched. The one that is the best match (matches the closest) is the plugin that is called. Usually this will be the longest pattern.
You can parameterize your URLs either with standard URL parameters in the query string (after the “?” character), or with attributes:
This would match only on URLs that had three components, the first of which is “myresource”. The second and third are put in as named attributes in the request.
Plugins whose WebContent attribute is “Static” contain resources that are served up automatically. Each resource in the plugin is made available at a URL that corresponds to the plugin’s URL plus the relative path of the resource.
You can write plugins to provide RESTful interfaces to Cycle Server functions. It is as easy as implementing methods for each of the four HTTP methods (GET, POST, PUT and DELETE).
Plugin Directory Layout
In this example, we’ll create a plugin called “example”.
Create the directory $CYCLESERVER_HOME/plugins/example
Create a config file in that directory example.cfg with the following contents:
# example.cfg WebContent = dynamic UriPatterns = /example AllowAnonymousAccess = true
Create a python file in that directory called example.py (see plugins configuration for a description of the config file) with the following contents:
example.py / GET
import time def get(request, response): output = time.asctime(time.localtime()) + "nn" # # show http headers # for h in request.headers().keys(): output += "header(%s): " % h + request.header(h) + "n" # # show query parameters # output += "n" for p in request.parameters().keys(): output += "parameter(%s): " % p + request.parameter(p) + "n" output += "n" response.write( output, 'text/plain' )
The code block above shows how to respond to a GET request. You can access the response headers and parameters as dictionaries using the headers() and parameters() methods. Call the write() method of the response object when you are ready to write out a response to the client. You can set the Content-Type of the response in the second argument to the write() method (the default is ‘text/plain’).
You can test your plugin with your browser or by using curl. Because we set the UriPatterns =
/example, the url would be http://server/example
Try adding query parameters to the url (like http://server/example?param1=foo) to see how they get added to the request object.
example.py / POST
def post(request, response): # posted data gets put in a key w/ empty string value in params() payload = '' for k,v in request.parameters().items(): # display parameters in logs/cycleserver.log application.logger.info("param %s => %s" % (k,v)) if v == '': payload = k daolyap = payload[::-1] # reverse payload response.write(daolyap)
You may log messages to logs/cycleserver.log by importing the application.logger plugin and calling its debug(), info() and error() methods.
import application.logger def get(request, response): application.logger.info("responding to GET request")
You can use the python debugger pdb to add breakpoints to your code and access the breakpoints using telnet or netcat.
To use pdb, first add the code for Remote Python Debugger (rpdb) to your component to src/main/component/lib/python/:
$ curl -L -O https://github.com/cyclecomputing/rpdb/archive/master.zip $ unzip master.zip $ cp -r rpdb-master/rpdb <your-component>/src/main/component/lib/python
Next add the breakpoint to your code:
# example.py import rpdb rpdb.set_trace()
Load the URL for your dynamic WebContent plugin in a browser. It should spin with the message “Waiting for Localhost”, this is because Tomcat is paused at the breakpoint.
To connect to pdb, run telnet localhost 4444.
See the section on HTML Template Plugins for information on HTML Template plugins.