001/*
002 * (C) Copyright 2014 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Maxime Hilaire
016 *
017 */
018package org.nuxeo.ecm.core.cache;
019
020import java.util.ArrayList;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027import org.nuxeo.runtime.model.ContributionFragmentRegistry;
028
029/**
030 * Registry to register cache
031 *
032 * @since 6.0
033 */
034public final class CacheRegistry extends ContributionFragmentRegistry<CacheDescriptor> {
035
036    private static final Log log = LogFactory.getLog(CacheRegistry.class);
037
038    // map of cache
039    protected final Map<String, CacheDescriptor> caches = new HashMap<String, CacheDescriptor>();
040
041    @Override
042    public String getContributionId(CacheDescriptor contrib) {
043        return contrib.name;
044    }
045
046    @Override
047    public void contributionUpdated(String id, CacheDescriptor descriptor, CacheDescriptor newOrigContrib) {
048        String name = descriptor.name;
049        if (name == null) {
050            throw new RuntimeException("The cache name must not be null!");
051        }
052        if (descriptor.remove) {
053            contributionRemoved(id, descriptor);
054            return;
055        }
056
057        if (caches.containsKey(name)) {
058            throw new IllegalStateException(String.format(
059                    "Another cache has already been registered for the given name %s", name));
060        }
061
062        caches.put(name, descriptor);
063        log.info("cache registered: " + name);
064    }
065
066    @Override
067    public boolean isSupportingMerge() {
068        return false;
069    }
070
071    @Override
072    public void contributionRemoved(String id, CacheDescriptor origContrib) {
073        String name = origContrib.name;
074        CacheDescriptor cache = caches.remove(name);
075        if (cache == null) {
076            throw new IllegalStateException("No such cache registered" + name);
077        }
078        try {
079            cache.stop();
080        } catch (RuntimeException e) {
081            log.error(String.format("Error while removing cache '%s'", name), e);
082        }
083        log.info("cache removed: " + name);
084    }
085
086    @Override
087    public CacheDescriptor clone(CacheDescriptor orig) {
088        return orig.clone();
089    }
090
091    @Override
092    public void merge(CacheDescriptor src, CacheDescriptor dst) {
093        boolean remove = src.remove;
094        // keep old remove info: if old contribution was removed, new one
095        // should replace the old one completely
096        if (remove) {
097            dst.remove = remove;
098            // don't bother merging
099            return;
100        }
101
102    }
103
104    public CacheAttributesChecker getCache(String name) {
105        if (caches.containsKey(name)) {
106            return caches.get(name).cacheChecker;
107        }
108        return null;
109    }
110
111    public List<CacheAttributesChecker> getCaches() {
112        List<CacheAttributesChecker> res = new ArrayList<CacheAttributesChecker>(caches.size());
113        for (CacheDescriptor desc : caches.values()) {
114            res.add(desc.cacheChecker);
115        }
116        return res;
117    }
118
119    public void start() {
120        RuntimeException errors = new RuntimeException("Cannot start caches, check suppressed error");
121        for (CacheDescriptor desc : caches.values()) {
122            try {
123                desc.start();
124            } catch (RuntimeException cause) {
125                errors.addSuppressed(cause);
126            }
127        }
128        if (errors.getSuppressed().length > 0) {
129            throw errors;
130        }
131    }
132
133    public void stop() {
134        RuntimeException errors = new RuntimeException("Cannot stop caches, check suppressed error");
135        for (CacheDescriptor desc : caches.values()) {
136            try {
137                desc.stop();
138            } catch (RuntimeException cause) {
139                errors.addSuppressed(cause);
140            }
141        }
142        if (errors.getSuppressed().length > 0) {
143            throw errors;
144        }
145    }
146
147}