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