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