001/*
002 * (C) Copyright 2014 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 *
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.model.ContributionFragmentRegistry;
030
031/**
032 * Registry to register cache
033 *
034 * @since 6.0
035 */
036public final class CacheRegistry extends ContributionFragmentRegistry<CacheDescriptor> {
037
038    private static final Log log = LogFactory.getLog(CacheRegistry.class);
039
040    // map of cache
041    protected final Map<String, CacheDescriptor> caches = new HashMap<String, CacheDescriptor>();
042
043    @Override
044    public String getContributionId(CacheDescriptor contrib) {
045        return contrib.name;
046    }
047
048    @Override
049    public void contributionUpdated(String id, CacheDescriptor descriptor, CacheDescriptor newOrigContrib) {
050        String name = descriptor.name;
051        if (name == null) {
052            throw new RuntimeException("The cache name must not be null!");
053        }
054        if (descriptor.remove) {
055            contributionRemoved(id, descriptor);
056            return;
057        }
058
059        if (caches.containsKey(name)) {
060            throw new IllegalStateException(String.format(
061                    "Another cache has already been registered for the given name %s", name));
062        }
063
064        caches.put(name, descriptor);
065        log.info("cache registered: " + name);
066    }
067
068    @Override
069    public boolean isSupportingMerge() {
070        return false;
071    }
072
073    @Override
074    public void contributionRemoved(String id, CacheDescriptor origContrib) {
075        String name = origContrib.name;
076        CacheDescriptor cache = caches.remove(name);
077        if (cache == null) {
078            throw new IllegalStateException("No such cache registered" + name);
079        }
080        try {
081            cache.stop();
082        } catch (RuntimeException e) {
083            log.error(String.format("Error while removing cache '%s'", name), e);
084        }
085        log.info("cache removed: " + name);
086    }
087
088    @Override
089    public CacheDescriptor clone(CacheDescriptor orig) {
090        return orig.clone();
091    }
092
093    @Override
094    public void merge(CacheDescriptor src, CacheDescriptor dst) {
095        boolean remove = src.remove;
096        // keep old remove info: if old contribution was removed, new one
097        // should replace the old one completely
098        if (remove) {
099            dst.remove = remove;
100            // don't bother merging
101            return;
102        }
103
104    }
105
106    public CacheAttributesChecker getCache(String name) {
107        if (caches.containsKey(name)) {
108            return caches.get(name).cacheChecker;
109        }
110        return null;
111    }
112
113    public List<CacheAttributesChecker> getCaches() {
114        List<CacheAttributesChecker> res = new ArrayList<CacheAttributesChecker>(caches.size());
115        for (CacheDescriptor desc : caches.values()) {
116            res.add(desc.cacheChecker);
117        }
118        return res;
119    }
120
121    public void start() {
122        RuntimeException errors = new RuntimeException("Cannot start caches, check suppressed error");
123        for (CacheDescriptor desc : caches.values()) {
124            try {
125                desc.start();
126            } catch (RuntimeException cause) {
127                errors.addSuppressed(cause);
128            }
129        }
130        if (errors.getSuppressed().length > 0) {
131            throw errors;
132        }
133    }
134
135    public void stop() {
136        RuntimeException errors = new RuntimeException("Cannot stop caches, check suppressed error");
137        for (CacheDescriptor desc : caches.values()) {
138            try {
139                desc.stop();
140            } catch (RuntimeException cause) {
141                errors.addSuppressed(cause);
142            }
143        }
144        if (errors.getSuppressed().length > 0) {
145            throw errors;
146        }
147    }
148
149}