package org.codelibs.elasticsearch.taste.rest; import static org.elasticsearch.rest.RestStatus.OK; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.codelibs.elasticsearch.taste.exception.InvalidParameterException; import org.codelibs.elasticsearch.taste.rest.handler.ItemRequestHandler; import org.codelibs.elasticsearch.taste.rest.handler.PreferenceRequestHandler; import org.codelibs.elasticsearch.taste.rest.handler.RequestHandler; import org.codelibs.elasticsearch.taste.rest.handler.RequestHandlerChain; import org.codelibs.elasticsearch.taste.rest.handler.UserRequestHandler; import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; import org.elasticsearch.rest.RestChannel; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.threadpool.ThreadPool; public class TasteEventRestAction extends BaseRestHandler { private final UserRequestHandler userRequestHandler; private final ItemRequestHandler itemRequestHandler; private final PreferenceRequestHandler preferenceRequestHandler; private final ThreadPool pool; @Inject public TasteEventRestAction(final Settings settings, final Client client, final RestController restController, final ThreadPool pool) { super(settings, restController, client); this.pool = pool; restController.registerHandler(RestRequest.Method.POST, "/{index}/_taste/event", this); restController.registerHandler(RestRequest.Method.POST, "/{index}/{type}/_taste/event", this); userRequestHandler = new UserRequestHandler(settings, client, pool); itemRequestHandler = new ItemRequestHandler(settings, client, pool); preferenceRequestHandler = new PreferenceRequestHandler(settings, client, pool); } @Override protected void handleRequest(final RestRequest request, final RestChannel channel, final Client client) { final String[] data = request.content().toUtf8() .split("\r\n|[\n\r\u2028\u2029\u0085]"); final Iterator<String> itr = Arrays.asList(data).iterator(); pool.generic().execute(()->execute(request, channel, itr)); } private void execute(final RestRequest request, final RestChannel channel, final Iterator<String> itr) { try { if (itr.hasNext()) { final String aData = itr.next(); final Map<String, Object> requestMap = XContentFactory .xContent(aData) .createParser(aData).map(); final Map<String, Object> paramMap = new HashMap<>(); final boolean hasUser = userRequestHandler.hasUser(requestMap); final boolean hasItem = itemRequestHandler.hasItem(requestMap); final boolean hasPreference = preferenceRequestHandler .hasPreference(requestMap); final RequestHandler continueExecuteHandler = (req, listener, reqMap, parMap, c) -> execute(request, channel, itr); if (hasPreference) { final RequestHandlerChain chain = new RequestHandlerChain( new RequestHandler[]{userRequestHandler, itemRequestHandler, preferenceRequestHandler, continueExecuteHandler}); chain.execute(request, createOnErrorListener(channel), requestMap, paramMap); } else if (hasUser) { final RequestHandlerChain chain = new RequestHandlerChain( new RequestHandler[]{userRequestHandler, continueExecuteHandler}); chain.execute(request, createOnErrorListener(channel), requestMap, paramMap); } else if (hasItem) { final RequestHandlerChain chain = new RequestHandlerChain( new RequestHandler[]{itemRequestHandler, continueExecuteHandler}); chain.execute(request, createOnErrorListener(channel), requestMap, paramMap); } else { throw new InvalidParameterException("No preference data."); } } else { final XContentBuilder builder = JsonXContent.contentBuilder(); final String pretty = request.param("pretty"); if (pretty != null && !"false".equalsIgnoreCase(pretty)) { builder.prettyPrint().lfAtEnd(); } builder.startObject(); builder.field("acknowledged", true); builder.endObject(); channel.sendResponse(new BytesRestResponse(OK, builder)); } } catch (final Exception e) { try { channel.sendResponse(new BytesRestResponse(channel, e)); } catch (final Exception ex) { logger.error("Failed to send a failure response.", ex); } } } private RequestHandler.OnErrorListener createOnErrorListener( final RestChannel channel) { return t -> { try { channel.sendResponse(new BytesRestResponse(channel, t)); } catch (final Exception e) { logger.error("Failed to send a failure response.", e); } }; } }