001/*
002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thierry Delprat <tdelprat@nuxeo.com>
018 */
019package org.nuxeo.elasticsearch.seqgen;
020
021import java.util.NoSuchElementException;
022
023import org.elasticsearch.action.index.IndexResponse;
024import org.elasticsearch.client.Client;
025import org.nuxeo.ecm.core.api.NuxeoException;
026import org.nuxeo.ecm.core.uidgen.AbstractUIDSequencer;
027import org.nuxeo.ecm.core.uidgen.UIDSequencer;
028import org.nuxeo.elasticsearch.ElasticSearchConstants;
029import org.nuxeo.elasticsearch.api.ElasticSearchAdmin;
030import org.nuxeo.runtime.api.Framework;
031
032/**
033 * Elasticsearch implementation of {@link UIDSequencer}.
034 * <p>
035 * Since elasticsearch does not seem to support a notion of native sequence, the implementation uses the auto-increment
036 * of the version attribute as described in the <a href=
037 * "http://blogs.perl.org/users/clinton_gormley/2011/10/elasticsearchsequence---a-blazing-fast-ticket-server.html"
038 * >ElasticSearch::Sequence - a blazing fast ticket server</a> blog post.
039 *
040 * @since 7.3
041 */
042public class ESUIDSequencer extends AbstractUIDSequencer {
043
044    protected Client esClient = null;
045
046    protected String indexName;
047
048    @Override
049    public void init() {
050        if (esClient != null) {
051            return;
052        }
053        ElasticSearchAdmin esa = Framework.getService(ElasticSearchAdmin.class);
054        esClient = esa.getClient();
055        indexName = esa.getIndexNameForType(ElasticSearchConstants.SEQ_ID_TYPE);
056        try {
057            boolean indexExists = esClient.admin().indices().prepareExists(indexName).execute().actionGet()
058                    .isExists();
059            if (!indexExists) {
060                throw new NuxeoException(
061                        String.format("Sequencer %s needs an elasticSearchIndex contribution with type %s", getName(),
062                                ElasticSearchConstants.SEQ_ID_TYPE));
063            }
064        } catch (NoSuchElementException | NuxeoException e) {
065            dispose();
066            throw e;
067        }
068    }
069
070    @Override
071    public void dispose() {
072        if (esClient == null) {
073            return;
074        }
075        esClient = null;
076        indexName = null;
077    }
078
079    @Override
080    public long getNextLong(String sequenceName) {
081        String source = "{ \"ts\" : " + System.currentTimeMillis() + "}";
082        IndexResponse res = esClient.prepareIndex(indexName, ElasticSearchConstants.SEQ_ID_TYPE, sequenceName).setSource(
083                source).execute().actionGet();
084        return res.getVersion();
085    }
086
087    @Override
088    public int getNext(String sequenceName) {
089        return (int) getNextLong(sequenceName);
090    }
091
092}