001/*
002 * (C) Copyright 2017 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.runtime.kv;
020
021import java.util.Map;
022import java.util.concurrent.ConcurrentHashMap;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026import org.nuxeo.runtime.model.ComponentInstance;
027import org.nuxeo.runtime.model.DefaultComponent;
028
029/**
030 * Implementation for the Key/Value Service.
031 *
032 * @since 9.1
033 */
034public class KeyValueServiceImpl extends DefaultComponent implements KeyValueService {
035
036    private static final Log log = LogFactory.getLog(KeyValueServiceImpl.class);
037
038    public static final int APPLICATION_STARTED_ORDER = -500;
039
040    public static final String CONFIG_XP = "configuration";
041
042    public static final String DEFAULT_STORE_ID = "default";
043
044    protected final KeyValueStoreRegistry registry = new KeyValueStoreRegistry();
045
046    protected Map<String, KeyValueStoreProvider> providers = new ConcurrentHashMap<>();
047
048    protected KeyValueStore defaultStore = new MemKeyValueStore();
049
050    @Override
051    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
052        switch (extensionPoint) {
053        case CONFIG_XP:
054            registerKeyValueStore((KeyValueStoreDescriptor) contribution);
055            break;
056        default:
057            throw new RuntimeException("Unknown extension point: " + extensionPoint);
058        }
059    }
060
061    @Override
062    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
063        switch (extensionPoint) {
064        case CONFIG_XP:
065            unregisterKeyValueStore((KeyValueStoreDescriptor) contribution);
066            break;
067        }
068    }
069
070    public void registerKeyValueStore(KeyValueStoreDescriptor descriptor) {
071        registry.addContribution(descriptor);
072        descriptorChanged(descriptor.name);
073        log.info("Registered key/value store: " + descriptor.name);
074    }
075
076    public void unregisterKeyValueStore(KeyValueStoreDescriptor descriptor) {
077        registry.removeContribution(descriptor);
078        descriptorChanged(descriptor.name);
079        log.info("Unregistered key/value store: " + descriptor.name);
080    }
081
082    @Override
083    public int getApplicationStartedOrder() {
084        return APPLICATION_STARTED_ORDER;
085    }
086
087    // ===== KeyValueService =====
088
089    @Override
090    public synchronized KeyValueStore getKeyValueStore(String name) {
091        KeyValueStoreProvider provider = providers.get(name);
092        if (provider == null) {
093            KeyValueStoreDescriptor descriptor = registry.getKeyValueStoreDescriptor(name);
094            if (descriptor == null) {
095                descriptor = registry.getKeyValueStoreDescriptor(DEFAULT_STORE_ID);
096                if (descriptor == null) {
097                    return defaultStore;
098                }
099            }
100            try {
101                provider = descriptor.getKlass().newInstance();
102                provider.initialize(descriptor);
103            } catch (ReflectiveOperationException e) {
104                throw new RuntimeException(e);
105            }
106            providers.put(name, provider);
107        }
108        return provider;
109    }
110
111    /* Close previous provider if we're overwriting it. */
112    protected synchronized void descriptorChanged(String name) {
113        KeyValueStoreProvider provider = providers.remove(name);
114        if (provider != null) {
115            provider.close();
116        }
117    }
118
119}