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.sql.coremodel;
020
021import java.lang.reflect.Field;
022import java.util.ArrayList;
023import java.util.List;
024
025import org.nuxeo.ecm.core.api.repository.FulltextConfiguration;
026import org.nuxeo.ecm.core.api.repository.Repository;
027import org.nuxeo.ecm.core.api.repository.RepositoryManager;
028import org.nuxeo.ecm.core.repository.RepositoryFactory;
029import org.nuxeo.ecm.core.repository.RepositoryService;
030import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor;
031import org.nuxeo.ecm.core.storage.sql.RepositoryImpl;
032import org.nuxeo.ecm.core.storage.sql.RepositoryManagement;
033import org.nuxeo.ecm.core.storage.sql.ra.PoolingRepositoryFactory;
034import org.nuxeo.runtime.api.Framework;
035import org.nuxeo.runtime.model.ComponentContext;
036import org.nuxeo.runtime.model.ComponentInstance;
037import org.nuxeo.runtime.model.DefaultComponent;
038import org.nuxeo.runtime.model.SimpleContributionRegistry;
039
040/**
041 * Service holding the configuration for VCS repositories.
042 *
043 * @since 5.9.3
044 */
045public class SQLRepositoryService extends DefaultComponent {
046
047    private static final String XP_REPOSITORY = "repository";
048
049    protected static final String CONNECTIONFACTORYIMPL_CLASS = "org.nuxeo.ecm.core.storage.sql.ra.ConnectionFactoryImpl";
050
051    protected RepositoryDescriptorRegistry registry = new RepositoryDescriptorRegistry();
052
053    protected static class RepositoryDescriptorRegistry extends SimpleContributionRegistry<RepositoryDescriptor> {
054
055        @Override
056        public String getContributionId(RepositoryDescriptor contrib) {
057            return contrib.name;
058        }
059
060        @Override
061        public RepositoryDescriptor clone(RepositoryDescriptor orig) {
062            return new RepositoryDescriptor(orig);
063        }
064
065        @Override
066        public void merge(RepositoryDescriptor src, RepositoryDescriptor dst) {
067            dst.merge(src);
068        }
069
070        @Override
071        public boolean isSupportingMerge() {
072            return true;
073        }
074
075        public void clear() {
076            currentContribs.clear();
077        }
078
079        public RepositoryDescriptor getRepositoryDescriptor(String id) {
080            return getCurrentContribution(id);
081        }
082
083        public List<String> getRepositoryIds() {
084            return new ArrayList<>(currentContribs.keySet());
085        }
086    }
087
088    @Override
089    public void activate(ComponentContext context) {
090        registry.clear();
091    }
092
093    @Override
094    public void deactivate(ComponentContext context) {
095        registry.clear();
096    }
097
098    @Override
099    public void registerContribution(Object contrib, String xpoint, ComponentInstance contributor) {
100        if (XP_REPOSITORY.equals(xpoint)) {
101            addContribution((RepositoryDescriptor) contrib);
102        } else {
103            throw new RuntimeException("Unknown extension point: " + xpoint);
104        }
105    }
106
107    @Override
108    public void unregisterContribution(Object contrib, String xpoint, ComponentInstance contributor) {
109        if (XP_REPOSITORY.equals(xpoint)) {
110            removeContribution((RepositoryDescriptor) contrib);
111        } else {
112            throw new RuntimeException("Unknown extension point: " + xpoint);
113        }
114    }
115
116    protected void addContribution(RepositoryDescriptor descriptor) {
117        registry.addContribution(descriptor);
118        updateRegistration(descriptor.name);
119    }
120
121    protected void removeContribution(RepositoryDescriptor descriptor) {
122        registry.removeContribution(descriptor);
123        updateRegistration(descriptor.name);
124    }
125
126    /**
127     * Update repository registration in high-level repository service.
128     */
129    protected void updateRegistration(String repositoryName) {
130        RepositoryManager repositoryManager = Framework.getService(RepositoryManager.class);
131        RepositoryDescriptor descriptor = registry.getRepositoryDescriptor(repositoryName);
132        if (descriptor == null) {
133            // last contribution removed
134            repositoryManager.removeRepository(repositoryName);
135            return;
136        }
137        // extract label, isDefault
138        // and pass it to high-level registry
139        RepositoryFactory repositoryFactory = new PoolingRepositoryFactory(repositoryName);
140        Repository repository = new Repository(repositoryName, descriptor.label, descriptor.isDefault(),
141                repositoryFactory);
142        repositoryManager.addRepository(repository);
143    }
144
145    public RepositoryDescriptor getRepositoryDescriptor(String name) {
146        return registry.getRepositoryDescriptor(name);
147    }
148
149    /**
150     * Gets the list of SQL repository names.
151     *
152     * @return the list of SQL repository names
153     * @since 5.9.5
154     */
155    public List<String> getRepositoryNames() {
156        return registry.getRepositoryIds();
157    }
158
159    /**
160     * Gets the low-level SQL Repository of the given name.
161     *
162     * @param repositoryName the repository name
163     * @return the repository
164     * @since 5.9.5
165     */
166    public RepositoryManagement getRepository(String repositoryName) {
167        RepositoryService repositoryService = Framework.getService(RepositoryService.class);
168        org.nuxeo.ecm.core.model.Repository repository = repositoryService.getRepository(repositoryName);
169        if (repository == null) {
170            throw new RuntimeException("Unknown repository: " + repositoryName);
171        }
172        if (repository instanceof org.nuxeo.ecm.core.storage.sql.Repository) {
173            // (JCA) ConnectionFactoryImpl already implements Repository
174            return (org.nuxeo.ecm.core.storage.sql.Repository) repository;
175        } else {
176            throw new RuntimeException("Unknown repository class: " + repository.getClass().getName());
177        }
178    }
179
180    public RepositoryImpl getRepositoryImpl(String repositoryName) {
181        RepositoryManagement repository = getRepository(repositoryName);
182        if (repository instanceof RepositoryImpl) {
183            return (RepositoryImpl) repository;
184        }
185        if (!CONNECTIONFACTORYIMPL_CLASS.equals(repository.getClass().getName())) {
186            throw new RuntimeException("Unknown repository class: " + repository.getClass());
187        }
188        try {
189            Field f1 = repository.getClass().getDeclaredField("managedConnectionFactory");
190            f1.setAccessible(true);
191            Object factory = f1.get(repository);
192            Field f2 = factory.getClass().getDeclaredField("repository");
193            f2.setAccessible(true);
194            return (RepositoryImpl) f2.get(factory);
195        } catch (SecurityException | NoSuchFieldException | IllegalAccessException e) {
196            throw new RuntimeException(e);
197        }
198    }
199
200    /**
201     * Gets the repositories as a list of {@link RepositoryManagement} objects.
202     *
203     * @since 5.9.5
204     * @return a list of {@link RepositoryManagement}
205     */
206    public List<RepositoryManagement> getRepositories() {
207        List<RepositoryManagement> repositories = new ArrayList<>();
208        for (String repositoryName : getRepositoryNames()) {
209            repositories.add(getRepository(repositoryName));
210        }
211        return repositories;
212    }
213
214    public FulltextConfiguration getFulltextConfiguration(String repositoryName) {
215        return getRepositoryImpl(repositoryName).getModel().getFulltextConfiguration();
216    }
217
218}