001/*
002 * (C) Copyright 2014-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 *     Maxime Hilaire
018 *     Thierry Martins
019 */
020package org.nuxeo.ecm.core.cache;
021
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.runtime.api.Framework;
030import org.nuxeo.runtime.model.ComponentContext;
031import org.nuxeo.runtime.model.ComponentInstance;
032import org.nuxeo.runtime.model.ComponentName;
033import org.nuxeo.runtime.model.DefaultComponent;
034import org.nuxeo.runtime.model.Extension;
035
036/**
037 * Cache service implementation to manage nuxeo cache
038 *
039 * @since 6.0
040 */
041public class CacheServiceImpl extends DefaultComponent implements CacheService {
042
043    /**
044     * @since 8.2
045     */
046    public static final String DEFAULT_CACHE_ID = "default-cache";
047
048    public static final ComponentName NAME = new ComponentName(CacheServiceImpl.class.getName());
049
050    private static final Log log = LogFactory.getLog(CacheServiceImpl.class);
051
052    protected final CacheRegistry cacheRegistry = new CacheRegistry();
053
054    /**
055     * Contains the names of all caches which have not been registered from an extension
056     */
057    protected final List<String> autoregisteredCacheNames = new ArrayList<>();
058
059    @Override
060    public Cache getCache(String name) {
061        return cacheRegistry.getCache(name);
062    }
063
064    @Override
065    public void deactivate(ComponentContext context) {
066        if (cacheRegistry.caches.size() > 0) {
067            Map<String, CacheDescriptor> descriptors = new HashMap<>(cacheRegistry.caches);
068            for (CacheDescriptor desc : descriptors.values()) {
069                cacheRegistry.contributionRemoved(desc.name, desc);
070                if (!autoregisteredCacheNames.remove(desc.name)) {
071                    log.warn("Unregistery leaked contribution " + desc.name);
072                }
073            }
074        }
075    }
076
077    @Override
078    public int getApplicationStartedOrder() {
079        ComponentInstance repositoryComponent = Framework.getRuntime().getComponentInstance(
080                "org.nuxeo.ecm.core.repository.RepositoryServiceComponent");
081        if (repositoryComponent == null || repositoryComponent.getInstance() == null) {
082            return super.getApplicationStartedOrder();
083        }
084        return ((DefaultComponent) repositoryComponent.getInstance()).getApplicationStartedOrder() - 5;
085    }
086
087    @Override
088    public void start(ComponentContext context) {
089        cacheRegistry.start();
090    }
091
092    @Override
093    public void stop(ComponentContext context) {
094        cacheRegistry.stop();
095    }
096
097    @Override
098    public void registerExtension(Extension extension) {
099        Object[] contribs = extension.getContributions();
100        for (Object contrib : contribs) {
101            CacheDescriptor descriptor = (CacheDescriptor) contrib;
102            registerCache(descriptor);
103        }
104    }
105
106    public void registerCache(CacheDescriptor descriptor) {
107        cacheRegistry.addContribution(descriptor);
108    }
109
110    @Override
111    public void registerCache(String name, int maxSize, int timeout) {
112        CacheDescriptor desc;
113        if (cacheRegistry.caches.get(DEFAULT_CACHE_ID) != null) {
114            desc = new CacheDescriptor(cacheRegistry.caches.get(DEFAULT_CACHE_ID));
115        } else {
116            desc = new CacheDescriptor();
117        }
118        desc.name = name;
119        desc.ttl = timeout;
120        desc.options.put("maxSize", String.valueOf(maxSize));
121        if (cacheRegistry.caches.get(name) == null) {
122            registerCache(desc);
123            autoregisteredCacheNames.add(name);
124        } else {
125            CacheDescriptor oldDesc = cacheRegistry.caches.get(name);
126            cacheRegistry.merge(oldDesc, desc);
127        }
128    }
129
130    @Override
131    public void unregisterExtension(Extension extension) throws RuntimeException {
132        Object[] contribs = extension.getContributions();
133        for (Object contrib : contribs) {
134            CacheDescriptor descriptor = (CacheDescriptor) contrib;
135            cacheRegistry.removeContribution(descriptor);
136        }
137    }
138
139    public void unregisterCache(CacheDescriptor descriptor) {
140        cacheRegistry.removeContribution(descriptor);
141    }
142
143    @Override
144    public <T> T getAdapter(Class<T> adapter) {
145        if (adapter.isAssignableFrom(CacheRegistry.class)) {
146            return adapter.cast(cacheRegistry);
147        }
148        return super.getAdapter(adapter);
149    }
150}