001/*
002 * (C) Copyright 2018 Nuxeo (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 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.uidgen;
020
021import static org.apache.commons.lang3.StringUtils.isBlank;
022
023import org.nuxeo.ecm.core.api.NuxeoException;
024import org.nuxeo.runtime.api.Framework;
025import org.nuxeo.runtime.kv.KeyValueService;
026import org.nuxeo.runtime.kv.KeyValueStore;
027import org.nuxeo.runtime.services.config.ConfigurationService;
028
029import java.util.ArrayList;
030import java.util.List;
031
032/**
033 * UID Sequencer based on a key/value store. The store is the same for all sequencers, but they are using different
034 * keys, prefixed by the sequencer name.
035 *
036 * @since 10.2
037 */
038public class KeyValueStoreUIDSequencer extends AbstractUIDSequencer {
039
040    /**
041     * Configuration property to specify the key/value store name. If none is specified, {@code sequence} is used.
042     */
043    public static final String STORE_NAME_PROPERTY = "nuxeo.uidseq.keyvaluestore.name";
044
045    public static final String DEFAULT_STORE_NAME = "sequence";
046
047    public static final String SEP = ".";
048
049    protected String storeName;
050
051    @Override
052    public void init() {
053        storeName = Framework.getService(ConfigurationService.class).getProperty(STORE_NAME_PROPERTY);
054        if (isBlank(storeName)) {
055            storeName = DEFAULT_STORE_NAME;
056        }
057    }
058
059    @Override
060    public void dispose() {
061        // nothing to do
062    }
063
064    protected KeyValueStore getStore() {
065        KeyValueStore store = Framework.getService(KeyValueService.class).getKeyValueStore(storeName);
066        if (store == null) {
067            throw new NuxeoException("Unknown key/value store: " + storeName);
068        }
069        return store;
070    }
071
072    protected String getKey(String key) {
073        return getName() + SEP + key;
074    }
075
076    @Override
077    public void initSequence(String key, long id) {
078        getStore().put(getKey(key), Long.valueOf(id));
079    }
080
081    @Override
082    public long getNextLong(String key) {
083        return getStore().addAndGet(getKey(key), 1);
084    }
085
086    @Override
087    public List<Long> getNextBlock(String key, int blockSize) {
088        List<Long> ret = new ArrayList<>(blockSize);
089        long last = getStore().addAndGet(getKey(key), blockSize);
090        for (int i = blockSize - 1; i >= 0; i--) {
091            ret.add(last - i);
092        }
093        return ret;
094    }
095}