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    @Override
064    public Cache getCache(String name) {
065        return cacheRegistry.getCache(name);
066    }
067
068    @Override
069    public void deactivate(ComponentContext context) {
070        if (cacheRegistry.caches.size() > 0) {
071            Map<String, CacheDescriptor> descriptors = new HashMap<String, CacheDescriptor>(cacheRegistry.caches);
072            for (CacheDescriptor desc : descriptors.values()) {
073                cacheRegistry.contributionRemoved(desc.name, desc);
074                if (!autoregisteredCacheNames.remove(desc.name)) {
075                    log.warn("Unregistery leaked contribution " + desc.name);
076                }
077            }
078        }
079    }
080
081    @Override
082    public int getApplicationStartedOrder() {
083        ComponentInstance repositoryComponent = Framework.getRuntime().getComponentInstance(
084                "org.nuxeo.ecm.core.repository.RepositoryServiceComponent");
085        if (repositoryComponent == null) {
086            return super.getApplicationStartedOrder();
087        }
088        return ((DefaultComponent) repositoryComponent.getInstance()).getApplicationStartedOrder() - 5;
089    }
090
091    @Override
092    public void applicationStarted(ComponentContext context) {
093        Framework.addListener(new RuntimeServiceListener() {
094
095            @Override
096            public void handleEvent(RuntimeServiceEvent event) {
097                if (RuntimeServiceEvent.RUNTIME_ABOUT_TO_STOP != event.id) {
098                    return;
099                }
100                Framework.removeListener(this);
101                cacheRegistry.stop();
102            }
103        });
104        cacheRegistry.start();
105    }
106
107    @Override
108    public void registerExtension(Extension extension) {
109        Object[] contribs = extension.getContributions();
110        for (Object contrib : contribs) {
111            CacheDescriptor descriptor = (CacheDescriptor) contrib;
112            registerCache(descriptor);
113        }
114    }
115
116    public void registerCache(CacheDescriptor descriptor) {
117        cacheRegistry.addContribution(descriptor);
118    }
119
120    @Override
121    public void registerCache(String name, int maxSize, int timeout) {
122        CacheDescriptor desc;
123        if (cacheRegistry.caches.get(DEFAULT_CACHE_ID) != null) {
124            desc = new CacheDescriptor(cacheRegistry.caches.get(DEFAULT_CACHE_ID));
125        } else {
126            desc = new CacheDescriptor();
127        }
128        desc.name = name;
129        desc.ttl = timeout;
130        desc.options.put("maxSize", String.valueOf(maxSize));
131        if (cacheRegistry.caches.get(name) == null) {
132            registerCache(desc);
133            autoregisteredCacheNames.add(name);
134        } else {
135            CacheDescriptor oldDesc = cacheRegistry.caches.get(name);
136            cacheRegistry.merge(oldDesc, desc);
137        }
138    }
139
140    @Override
141    public void unregisterExtension(Extension extension) throws RuntimeException {
142        Object[] contribs = extension.getContributions();
143        for (Object contrib : contribs) {
144            CacheDescriptor descriptor = (CacheDescriptor) contrib;
145            cacheRegistry.removeContribution(descriptor);
146        }
147    }
148
149    public void unregisterCache(CacheDescriptor descriptor) {
150        cacheRegistry.removeContribution(descriptor);
151    }
152
153
154    @Override
155    public <T> T getAdapter(Class<T> adapter) {
156        if (adapter.isAssignableFrom(CacheRegistry.class)) {
157            return adapter.cast(cacheRegistry);
158        }
159        return super.getAdapter(adapter);
160    }
161}