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