I thought it would be great (and maybe useful for you) to publish here my experience how to set up Trac with RPC over JSON. When I tried to do it from the scratch I had realized that a lot of things work in unexpected way, at least for me.
The main goal is to manage Trac tickets with some application. Here you'll get all information about plugin http://trac-hacks.org/wiki/XmlRpcPlugin. I want to make some details clear for you and show you my ready/worked code.
Ok. Short list of items.
The main goal is to manage Trac tickets with some application. Here you'll get all information about plugin http://trac-hacks.org/wiki/XmlRpcPlugin. I want to make some details clear for you and show you my ready/worked code.
Trac and Apache
Ok. Short list of items.
- install trac;
- install plugin 'TracXMLRPC';
- enable plugin (tracrpc.* = enabled in trac.ini, see below);
- set up web server with authorization;
- create user with 'XML_RPC' privileges in trac;
- it's really simple, use Basic Authorization (see below green pieces of text);
- create user ('htpasswd') and grant its to 'XML_PRC' (
trac-admin /path/to/projenv permission add user_name XML_PRC
); - Also, you maybe would be interested to set up mixed Authorization (fixed files + LDAP), see orange pieces of text below);
- In Java (see below):
- do auth;
- create JSON;
- send and interpret.
Apache configuration
<IfModule wsgi_module> WSGIScriptAlias /trac /path_to_trac/trac_site/cgi-bin/trac.wsgi WSGIPassAuthorization On <Directory /path_to_trac/trac_site/cgi-bin> WSGIApplicationGroup %{GLOBAL} Require all granted AllowOverride None Order allow,deny Allow from all </Directory> <Location /commref_req_trac/login> AuthBasicProvider file ldap AuthType Basic #AuthzLDAPAuthoritative off AuthUserFile /path_to_trac/trac_env/passwd_file AuthName "Trac" AuthLDAPURL "ldap://domain.com:389/dc=domain,dc=com?sAMAccountName?sub?(objectClass=user)" AuthLDAPBindDN "CN=user_ldap,OU=Service Accounts,OU=GROUP,DC=domain,DC=com" AuthLDAPBindPassword "user_ldap_password" Require valid-user </Location> </IfModule>
Trac configuration
[components]
tracrpc.* = enabled
Java
Transport
How to interact with Trac. For JSON I used library 'org.json' ('https://github.com/douglascrockford/JSON-java') and 'Apache Commons Codec' ('http://commons.apache.org/proper/commons-codec/') for Base64.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; import org.apache.commons.codec.binary.Base64; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public class TracAPI { private static int jsonIdSequence = 1; public static JSONObject sendJsonRpc(String method, JSONArray parameters) throws IOException, JSONException { JSONObject rpc = new JSONObject(); rpc.put("method", method); rpc.put("params", parameters); rpc.put("id", jsonIdSequence++); String tracUrl = Configuration.getTracApiUrl(); String tracUsername = Configuration.getTracApiUsername(); String tracPassword = Configuration.getTracApiPassword(); URL url = new URL(tracUrl); URLConnection conn = url.openConnection(); String userpass = tracUsername + ":" + tracPassword; String basicAuth = "Basic " + new String(new Base64().encode(userpass.getBytes())); conn.setRequestProperty ("Authorization", basicAuth); conn.setRequestProperty ("Content-Type", "application/json"); conn.setDoOutput(true); OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); Logger.debug("jsonrpc request:\n" + rpc.toString()); wr.write(rpc.toString()); wr.flush(); wr.close(); BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; String jsonText = ""; while ((line = rd.readLine()) != null) { jsonText += line; } rd.close(); Logger.debug("jsonrpc response:\n" + jsonText); return new JSONObject(jsonText); } }
Payload
read ticket
JSONArray parameters = new JSONArray(); parameters.put(ticketId); //id JSONObject resp = TracAPI.sendJsonRpc("ticket.get", parameters); String status = resp.getJSONArray("result").getJSONObject(3).getString("status"); String resolution = resp.getJSONArray("result").getJSONObject(3).getString("resolution"); String owner = resp.getJSONArray("result").getJSONObject(3).getString("owner");
create ticket
JSONArray parameters = new JSONArray(); parameters.put("summary text"); //summary parameters.put("description text"); //description parameters.put(new JSONObject()); //attributes parameters.put(false); //notify JSONObject resp = TracAPI.sendJsonRpc("ticket.create", parameters);
update/modify ticket
Update must be performed in two stages:- Determine (current) version (timestamp) of ticket (to protect ticket from concurrent modifications, you have to indicate which version of ticket you're modifying);
- Perform modification.
Determine timestamp.
JSONArray parameters = new JSONArray(); parameters.put(ticketId); //id JSONObject resp = TracAPI.sendJsonRpc("ticket.get", parameters); long ts = resp.getJSONArray("result").getJSONObject(3).getLong("_ts");
Update.
JSONObject attrs = new JSONObject(); attrs.put("action", "accept"); attrs.put("_ts", ts); parameters = new JSONArray(); parameters.put(ticketId); // id parameters.put("comment text"); // comment parameters.put(attrs); // attributes parameters.put(false); // notify resp = TracAPI.sendJsonRpc("ticket.update", parameters);
Feel free to write comments if you have questions/suggestions or another stuff you'd like to share. Thank you.
Java code was highlighted with "http://markup.su/highlighter/".
No comments:
Post a Comment