de.dev.eth0.elasticsearch.aem.indexing.ElasticSearchTransportHandler.java Source code

Java tutorial

Introduction

Here is the source code for de.dev.eth0.elasticsearch.aem.indexing.ElasticSearchTransportHandler.java

Source

/*
 * #%L
 * dev-eth0.de
 * %%
 * Copyright (C) 2016 dev-eth0.de
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package de.dev.eth0.elasticsearch.aem.indexing;

import com.day.cq.replication.AgentConfig;
import com.day.cq.replication.ReplicationActionType;
import com.day.cq.replication.ReplicationContent;
import com.day.cq.replication.ReplicationException;
import com.day.cq.replication.ReplicationLog;
import com.day.cq.replication.ReplicationResult;
import com.day.cq.replication.ReplicationTransaction;
import com.day.cq.replication.TransportContext;
import com.day.cq.replication.TransportHandler;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.dev.eth0.elasticsearch.aem.service.ElasticSearchService;
import java.io.IOException;
import java.util.Collections;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.apache.sling.commons.json.JSONException;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * TransportHandler Implementation that posts a ReplicationContent created by {@link ElasticSearchIndexContentBuilder} to a configured ElasticSearch.
 */
@Service(TransportHandler.class)
@Component(label = "Elastic Search Index Agent", immediate = true)
@Properties(@Property(name = Constants.SERVICE_RANKING, intValue = 1000))
public class ElasticSearchTransportHandler implements TransportHandler {

    @Reference
    protected ElasticSearchService elasticSearchService;

    private static final Logger LOG = LoggerFactory.getLogger(ElasticSearchTransportHandler.class);

    /**
     *
     * @param config
     * @return only accept if the serializationType is "elastic"
     */
    @Override
    public boolean canHandle(AgentConfig config) {
        return StringUtils.equalsIgnoreCase(config.getSerializationType(), ElasticSearchIndexContentBuilder.NAME);
    }

    /**
     *
     * @param ctx
     * @param tx
     * @return
     * @throws ReplicationException
     */
    @Override
    public ReplicationResult deliver(TransportContext ctx, ReplicationTransaction tx) throws ReplicationException {
        ReplicationLog log = tx.getLog();
        try {
            RestClient restClient = elasticSearchService.getRestClient();
            ReplicationActionType replicationType = tx.getAction().getType();
            if (replicationType == ReplicationActionType.TEST) {
                return doTest(ctx, tx, restClient);
            } else {
                log.info(getClass().getSimpleName() + ": ---------------------------------------");
                if (tx.getContent() == ReplicationContent.VOID) {
                    LOG.warn("No Replication Content provided");
                    return new ReplicationResult(true, 0,
                            "No Replication Content provided for path " + tx.getAction().getPath());
                }
                switch (replicationType) {
                case ACTIVATE:
                    return doActivate(ctx, tx, restClient);
                case DEACTIVATE:
                    return doDeactivate(ctx, tx, restClient);
                default:
                    log.warn(getClass().getSimpleName() + ": Replication action type" + replicationType
                            + " not supported.");
                    throw new ReplicationException(
                            "Replication action type " + replicationType + " not supported.");
                }
            }
        } catch (JSONException jex) {
            LOG.error("JSON was invalid", jex);
            return new ReplicationResult(false, 0, jex.getLocalizedMessage());
        } catch (IOException ioe) {
            log.error(getClass().getSimpleName() + ": Could not perform Indexing due to "
                    + ioe.getLocalizedMessage());
            LOG.error("Could not perform Indexing", ioe);
            return new ReplicationResult(false, 0, ioe.getLocalizedMessage());
        }
    }

    private ReplicationResult doDeactivate(TransportContext ctx, ReplicationTransaction tx, RestClient restClient)
            throws ReplicationException, JSONException, IOException {
        ReplicationLog log = tx.getLog();

        ObjectMapper mapper = new ObjectMapper();
        IndexEntry content = mapper.readValue(tx.getContent().getInputStream(), IndexEntry.class);
        Response deleteResponse = restClient.performRequest("DELETE",
                "/" + content.getIndex() + "/" + content.getType() + "/" + DigestUtils.md5Hex(content.getPath()),
                Collections.<String, String>emptyMap());
        LOG.debug(deleteResponse.toString());
        log.info(getClass().getSimpleName() + ": Delete Call returned "
                + deleteResponse.getStatusLine().getStatusCode() + ": "
                + deleteResponse.getStatusLine().getReasonPhrase());
        if (deleteResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED
                || deleteResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return ReplicationResult.OK;
        }
        LOG.error("Could not delete " + content.getType() + " at " + content.getPath());
        return new ReplicationResult(false, 0, "Replication failed");
    }

    /**
     * Perform the replication. All logic is covered in {@link ElasticSearchIndexContentBuilder} so we only need to transmit the JSON to ElasticSearch
     *
     * @param ctx
     * @param tx
     * @param restClient
     * @return
     * @throws ReplicationException
     */
    private ReplicationResult doActivate(TransportContext ctx, ReplicationTransaction tx, RestClient restClient)
            throws ReplicationException, JSONException, IOException {
        ReplicationLog log = tx.getLog();
        ObjectMapper mapper = new ObjectMapper();
        IndexEntry content = mapper.readValue(tx.getContent().getInputStream(), IndexEntry.class);
        if (content != null) {
            log.info(getClass().getSimpleName() + ": Indexing " + content.getPath());
            String contentString = mapper.writeValueAsString(content.getContent());
            log.debug(getClass().getSimpleName() + ": Index-Content: " + contentString);
            LOG.debug("Index-Content: " + contentString);

            HttpEntity entity = new NStringEntity(contentString, "UTF-8");
            Response indexResponse = restClient.performRequest("PUT",
                    "/" + content.getIndex() + "/" + content.getType() + "/"
                            + DigestUtils.md5Hex(content.getPath()),
                    Collections.<String, String>emptyMap(), entity);
            LOG.debug(indexResponse.toString());
            log.info(getClass().getSimpleName() + ": " + indexResponse.getStatusLine().getStatusCode() + ": "
                    + indexResponse.getStatusLine().getReasonPhrase());
            if (indexResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED
                    || indexResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                return ReplicationResult.OK;
            }
        }
        LOG.error("Could not replicate");
        return new ReplicationResult(false, 0, "Replication failed");
    }

    /**
     * Test Connection to ElasticSearch by getting basic informations
     *
     * @param ctx
     * @param tx
     * @param restClient
     * @return
     * @throws ReplicationException
     */
    private ReplicationResult doTest(TransportContext ctx, ReplicationTransaction tx, RestClient restClient)
            throws ReplicationException, IOException {
        ReplicationLog log = tx.getLog();
        Response response = restClient.performRequest("GET", "/", Collections.singletonMap("pretty", "true"));
        log.info(getClass().getSimpleName() + ": ---------------------------------------");
        log.info(getClass().getSimpleName() + ": " + response.toString());
        log.info(getClass().getSimpleName() + ": " + EntityUtils.toString(response.getEntity()));
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            return ReplicationResult.OK;
        }
        return new ReplicationResult(false, 0, "Replication test failed");
    }

}