package votorola.s.wap; // Copyright 2012. Christian Weilbach. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import java.io.IOException; import com.google.gson.stream.JsonWriter; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; import javax.mail.internet.AddressException; import votorola.g.lang.ThreadRestricted; import votorola.g.logging.LoggerX; import votorola.a.diff.DiffKeyParse; import votorola.a.diff.harvest.cache.HarvestCache; import votorola.a.voter.IDPair; import votorola.a.web.wap.Call; import votorola.a.web.wap.Requesting; import votorola.a.web.wap.Responding; import votorola.a.web.wap.WAP; import votorola.a.web.wap.ResponseConfiguration; import votorola.g.web.HTTPRequestException; import votorola.g.web.HTTPServletRequestX; /** * A web API for the harvested messages. An example request is: * *
* *
 * http://reluk.ca:8080/v/wap?wCall=hHarvest&hPoll=Sys/p/sandbox&hUser=Jill-ProviderNet&hStartDate=1330969452&wPretty
 * 
* *
* *

Query parameters

* *

* These are the specific parameters for the harvest cache API. See also the * general parameters for the {@linkplain WAP web API}. The examples shown below * assume a call prefix of 'h', but the actual prefix depends on the * {@linkplain WAP wCall} request parameter. Newest are first in the returned * JSON Array. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
KeyValueDefault
hPollNames the poll.Empty, optional item.
hUserSpecify 'hUser=Jim-MailCom' to request messages from a specific user(s).Empty, optional item.
hIdSpecify 'hId=1234' to only request messages newer than this serial. This * allows you to update a list by only fetching newer slices.Empty, optional item.
* *

Response

* *

* The response includes the following components. These are shown in JSON * format, with explanatory comments: *

* *
 * {
 *    "h": [
 *     {
 *        "id": 16,
 *        "sender": "Mike-ZeleaCom",
 *        "message": {
 *           "content": "At the bottom: (That's our new hack/prototype of a difference bridge. It's ugly as sin. It works poorly on these drafts too, because of the long wrapped ",
 *           "location": "http://mail.zelea.com/list/votorola/2010-May/000369.html"
 *        },
 *        "difference": {
 *           "key": "2891.2893",
 *           "selectand": "a"
 *        }
 *     },
 * }
 * 
*/ public @ThreadRestricted("constructor") final class HarvestWAP extends Call { /** * The name to use in the {@link WAP wCall} query parameter, which is * * * * * {@value} . For example: wCall=hHarvest. */ public static final String CALL_TYPE = "Harvest"; private static final Logger LOGGER = LoggerX.i(HarvestWAP.class); // error handling private final static String ERROR = "Could not initialize harvest WAP service."; private String errorMessage; private final boolean isInit; // started successfully? // parameters extracted from HTTP GET request private final String poll; private final String[] users; private final int id; /** * Constructs a HarvestWAP. This service is used by * {@linkplain votorola.s.gwt.stage.talk.TalkTrack} * * @param _prefix * @param _req * @param _resConfig * @throws HTTPRequestException */ public HarvestWAP(String _prefix, Requesting _req, ResponseConfiguration _resConfig) throws HTTPRequestException { super(_prefix, _req, _resConfig); boolean tmpInit = false; int tempId = 0; String tempPoll = null; String tempUsers = null; String tempMessage = null; try { tempPoll = HTTPServletRequestX.getParameterNonEmpty(prefix() + "Poll", req().request()); tempUsers = HTTPServletRequestX.getParameterNonEmpty(prefix() + "Users", req().request()); final String preId = HTTPServletRequestX.getParameterNonEmpty( prefix() + "Id", req().request()); tempId = preId == null ? 0 : Integer.valueOf(preId); tmpInit = true; } catch (Exception e) { tempMessage = e.getMessage(); LOGGER.log(Level.WARNING, ERROR, e); } poll = tempPoll; users = (tempUsers != null) ? tempUsers.split(",") : null; id = tempId; isInit = tmpInit; errorMessage = tempMessage; } /** * Servlet response, streaming out JSON from the * {@linkplain votorola.a.diff.harvest.cache.DiffMessageTable}. */ @Override public void respond(Responding res) throws IOException { // This method is also called by the default implementation of doHead(), // which discards the response body after learning its length. try { // LOGGER.fine(votorola.g.web.HTTPServletRequestX.buildRequestSummary( // res.request()).toString()); //// WAP.doGet already fine-logs request, echoing same info clutters log, CWFIX final JsonWriter out = res.outJSON(); if (!isInit) { error(out, errorMessage); return; // init error } // synchronization to ensure the statement is not reused while we // still use // the result set. this is only for prototyping and very slow synchronized (req().wap().vsRun().database()) { ResultSet rs = null; try { rs = HarvestCache.init(req().wap().vsRun()).getTable() .get(poll, users, id); } catch (AddressException | SQLException e) { LOGGER.log(Level.WARNING, "Cannot fetch ResultSet. ", e); error(out, e.getLocalizedMessage()); return; } // start regular output out.name(prefix()).beginArray(); while (rs.next()) { out.beginObject(); // id, sender, addressee, pollname, content, base_url, path, // sent_ts, a, ar, b, br, selectand out.name("id").value(rs.getInt(1)); // out.name("pollname").value(rs.getString(4)); out.name("sender") .value(IDPair.toUsername(rs.getString(2))); out.name("addressee") .value(IDPair.toUsername(rs.getString(3))); out.name("sentDate").value(rs.getTimestamp(8).getTime()); // message out.name("message").beginObject(); out.name("content").value(rs.getString(5)); out.name("location").value(rs.getString(6)/* base_url */ + rs.getString(7)/* path */); out.endObject(); // difference out.name("difference").beginObject(); out.name("key").value(new DiffKeyParse(rs.getInt(9), // CWFIX obsolete form rs.getInt(10), rs.getInt(11), rs.getInt(12)).key()); out.name("selectand").value(rs.getString(13)); out.endObject(); /* out.name("sent_ts").value(rs.getTimestamp(12).getTime()); */ // bite.setRelation(HarvestCache.i().relation(rs.getString(2),rs.getString(3),rs.getString(4)).symbol()); out.endObject(); } rs.close(); out.endArray(); } } catch (RuntimeException | SQLException x) { LOGGER.log(LoggerX.WARNING, /* message */"", x); } } private void error(final JsonWriter out, final String errorMessage) throws IOException { out.name("error").value(errorMessage); } }