001/*
002 * (C) Copyright 2014 Nuxeo SA (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 *     Florent Guillaume
016 */
017package org.nuxeo.ecm.core.storage.lock;
018
019import java.lang.reflect.Constructor;
020import java.lang.reflect.InvocationTargetException;
021import java.util.Map;
022import java.util.concurrent.ConcurrentHashMap;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026import org.nuxeo.ecm.core.api.NuxeoException;
027import org.nuxeo.ecm.core.model.LockManager;
028import org.nuxeo.runtime.model.ComponentContext;
029import org.nuxeo.runtime.model.ComponentInstance;
030import org.nuxeo.runtime.model.DefaultComponent;
031import org.nuxeo.runtime.model.SimpleContributionRegistry;
032
033/**
034 * Service holding the registered lock managers.
035 * <p>
036 * Actual instantiation is done by storage backends.
037 *
038 * @since 6.0
039 */
040public class LockManagerService extends DefaultComponent {
041
042    private static final Log log = LogFactory.getLog(LockManagerService.class);
043
044    private static final String XP_LOCKMANAGER = "lockmanager";
045
046    protected LockManagerDescriptorRegistry registry = new LockManagerDescriptorRegistry();
047
048    protected Map<String, LockManager> lockManagers = new ConcurrentHashMap<>();
049
050    protected static class LockManagerDescriptorRegistry extends SimpleContributionRegistry<LockManagerDescriptor> {
051
052        @Override
053        public String getContributionId(LockManagerDescriptor contrib) {
054            return contrib.name;
055        }
056
057        @Override
058        public LockManagerDescriptor clone(LockManagerDescriptor orig) {
059            return new LockManagerDescriptor(orig);
060        }
061
062        @Override
063        public void merge(LockManagerDescriptor src, LockManagerDescriptor dst) {
064            dst.merge(src);
065        }
066
067        @Override
068        public boolean isSupportingMerge() {
069            return true;
070        }
071
072        public void clear() {
073            currentContribs.clear();
074        }
075
076        public LockManagerDescriptor getLockManagerDescriptor(String id) {
077            return getCurrentContribution(id);
078        }
079    }
080
081    @Override
082    public void activate(ComponentContext context) {
083        registry.clear();
084    }
085
086    @Override
087    public void deactivate(ComponentContext context) {
088        registry.clear();
089    }
090
091    @Override
092    public void registerContribution(Object contrib, String xpoint, ComponentInstance contributor) {
093        if (XP_LOCKMANAGER.equals(xpoint)) {
094            addContribution((LockManagerDescriptor) contrib);
095        } else {
096            throw new NuxeoException("Unknown extension point: " + xpoint);
097        }
098    }
099
100    @Override
101    public void unregisterContribution(Object contrib, String xpoint, ComponentInstance contributor) {
102        if (XP_LOCKMANAGER.equals(xpoint)) {
103            removeContribution((LockManagerDescriptor) contrib);
104        } else {
105            throw new NuxeoException("Unknown extension point: " + xpoint);
106        }
107    }
108
109    protected void addContribution(LockManagerDescriptor descriptor) {
110        log.info("Registered " + descriptor);
111        registry.addContribution(descriptor);
112    }
113
114    protected void removeContribution(LockManagerDescriptor descriptor) {
115        log.info("Unregistered " + descriptor);
116        registry.removeContribution(descriptor);
117    }
118
119    /**
120     * Returns the lock manager registered with the given name.
121     * <p>
122     * Lazily constructs it if needed.
123     *
124     * @param name the lock manager name
125     * @return the lock manager, or {@code null} if none is registered
126     * @since 6.0
127     */
128    public synchronized LockManager getLockManager(String name) {
129        LockManager lockManager = lockManagers.get(name);
130        if (lockManager == null) {
131            LockManagerDescriptor descriptor = registry.getLockManagerDescriptor(name);
132            if (descriptor == null) {
133                return null;
134            }
135            try {
136                Constructor<? extends LockManager> ctor = descriptor.klass.getConstructor(String.class);
137                lockManager = ctor.newInstance(name);
138            } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException
139                    | InvocationTargetException e) {
140                throw new NuxeoException(e);
141            }
142            registerLockManager(name, lockManager);
143        }
144        return lockManager;
145    }
146
147    // used by unit tests
148    public void registerLockManager(String name, LockManager lockManager) {
149        lockManagers.put(name, lockManager);
150    }
151
152    /**
153     * @since 7.4
154     */
155    public void unregisterLockManager(String name) {
156        lockManagers.remove(name);
157    }
158
159}