001/*
002 *  Copyright 2016 Anyware Services
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 */
016package org.ametys.plugins.repository.provider;
017
018import java.util.List;
019import java.util.Map;
020
021import javax.jcr.RepositoryException;
022
023import org.apache.jackrabbit.core.cluster.UpdateEventChannel;
024import org.apache.jackrabbit.core.id.NodeId;
025import org.apache.jackrabbit.core.id.PropertyId;
026import org.apache.jackrabbit.core.persistence.PMContext;
027import org.apache.jackrabbit.core.persistence.PersistenceManager;
028import org.apache.jackrabbit.core.persistence.check.ConsistencyCheckListener;
029import org.apache.jackrabbit.core.persistence.check.ConsistencyReport;
030import org.apache.jackrabbit.core.persistence.pool.BundleDbPersistenceManager;
031import org.apache.jackrabbit.core.persistence.pool.DerbyPersistenceManager;
032import org.apache.jackrabbit.core.persistence.pool.MySqlPersistenceManager;
033import org.apache.jackrabbit.core.persistence.pool.OraclePersistenceManager;
034import org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager;
035import org.apache.jackrabbit.core.persistence.util.NodeInfo;
036import org.apache.jackrabbit.core.state.ChangeLog;
037import org.apache.jackrabbit.core.state.ItemStateException;
038import org.apache.jackrabbit.core.state.NoSuchItemStateException;
039import org.apache.jackrabbit.core.state.NodeReferences;
040import org.apache.jackrabbit.core.state.NodeState;
041import org.apache.jackrabbit.core.state.PropertyState;
042import org.apache.jackrabbit.core.util.db.ConnectionFactory;
043
044import org.ametys.core.datasource.AbstractDataSourceManager.DataSourceDefinition;
045import org.ametys.core.datasource.ConnectionHelper;
046import org.ametys.runtime.config.Config;
047
048/**
049 * Ametys implementation of Jackrabbit's {@link PersistenceManager}.
050 * This implementation is only a wrapper to an actual {@link BundleDbPersistenceManager}, depending on the config parameter.
051 */
052public class AmetysPersistenceManager extends BundleDbPersistenceManager
053{
054    /**
055     * Config parameter's name to use default Jackrabbit behaviour.
056     */
057    public static final String CONFIG_USE_DEFAULT = "org.ametys.plugins.repository.default-datasource";
058    
059    /**
060     * Config parameter's name referencing the datasource to use.
061     */
062    public static final String CONFIG_PM_DATASOURCE = "org.ametys.plugins.repository.datasource";
063    
064    private BundleDbPersistenceManager _wrappedPM;
065    private boolean _useDefault;
066    private String _workspace;
067    
068    /**
069     * Constructor.
070     */
071    public AmetysPersistenceManager()
072    {
073        _useDefault = Config.getInstance().getValue(CONFIG_USE_DEFAULT);
074        
075        if (_useDefault)
076        {
077            _wrappedPM = new DerbyPersistenceManager();
078            _wrappedPM.setSchemaObjectPrefix("");
079            _wrappedPM.setExternalBLOBs(true);
080        }
081        else
082        {
083            String datasource = Config.getInstance().getValue(CONFIG_PM_DATASOURCE);
084            
085            DataSourceDefinition dsDefinition = ConnectionHelper.getDataSourceDefinition(datasource);
086            
087            Map<String, Object> parameters = dsDefinition.getParameters();
088            String defUrl = (String) parameters.get("url");
089            String defDriver = (String) parameters.get("driver");
090            String defUser = (String) parameters.get("user");
091            String defPassword = (String) parameters.get("password");
092            
093            String dbType = ConnectionHelper.getDatabaseType(defUrl);
094            switch (dbType)
095            {
096                case ConnectionHelper.DATABASE_DERBY:
097                    _wrappedPM = new DerbyPersistenceManager();
098                    break;
099                case ConnectionHelper.DATABASE_MYSQL:
100                    _wrappedPM = new MySqlPersistenceManager();
101                    break;
102                case ConnectionHelper.DATABASE_ORACLE:
103                    _wrappedPM = new OraclePersistenceManager();
104                    break;
105                case ConnectionHelper.DATABASE_POSTGRES:
106                    _wrappedPM = new PostgreSQLPersistenceManager();
107                    break;
108                default:
109                    throw new IllegalArgumentException("Datasource URL " + defUrl + " is not supported for Jackrabbit PersistenceManagers.");
110            }
111            
112            _wrappedPM.setUrl(defUrl);
113            _wrappedPM.setDriver(defDriver);
114            _wrappedPM.setUser(defUser);
115            _wrappedPM.setPassword(defPassword);
116        }
117    }
118    
119    /**
120     * Get the wrapped persistence manager
121     * @return the persistence manager
122     */
123    public BundleDbPersistenceManager getWrappedPM()
124    {
125        return _wrappedPM;
126    }
127
128    /**
129     * Indicates the current JCR workspace.
130     * @param workspace the JCR workspace.
131     */
132    public void setWorkspace(String workspace)
133    {
134        _workspace = workspace;
135    }
136    
137    // Unsupported methods
138    
139    @Override
140    public void setUrl(String newUrl)
141    {
142        throw new UnsupportedOperationException("setUrl() method is not supported for AmetysPersistenceManager.");
143    }
144    
145    @Override
146    public void setUser(String unused)
147    {
148        throw new UnsupportedOperationException("setUser() method is not supported for AmetysPersistenceManager.");
149    }
150    
151    @Override
152    public void setPassword(String unused)
153    {
154        throw new UnsupportedOperationException("setPassword() method is not supported for AmetysPersistenceManager.");
155    }
156    
157    @Override
158    public void setDriver(String unused)
159    {
160        throw new UnsupportedOperationException("setDriver() method is not supported for AmetysPersistenceManager.");
161    }
162    
163    // PersistenceManager methods
164
165    @Override
166    public void init(PMContext ctx) throws Exception
167    {
168        if (_useDefault)
169        {
170            String dbUrl = "jdbc:derby:" + ctx.getHomeDir().getCanonicalPath() + "/db;create=true";
171            _wrappedPM.setUrl(dbUrl);
172        }
173        else
174        {
175            String prefix = _workspace  == null ? "version_" : _workspace + "_";
176            _wrappedPM.setSchemaObjectPrefix(prefix);
177        }
178        
179        _wrappedPM.init(ctx);
180    }
181
182    @Override
183    public void close() throws Exception
184    {
185        _wrappedPM.close();
186    }
187
188    @Override
189    public NodeState createNew(NodeId id)
190    {
191        return _wrappedPM.createNew(id);
192    }
193
194    @Override
195    public PropertyState createNew(PropertyId id)
196    {
197        return _wrappedPM.createNew(id);
198    }
199
200    @Override
201    public NodeState load(NodeId id) throws NoSuchItemStateException, ItemStateException
202    {
203        return _wrappedPM.load(id);
204    }
205
206    @Override
207    public PropertyState load(PropertyId id) throws NoSuchItemStateException, ItemStateException
208    {
209        return _wrappedPM.load(id);
210    }
211
212    @Override
213    public NodeReferences loadReferencesTo(NodeId id) throws NoSuchItemStateException, ItemStateException
214    {
215        return _wrappedPM.loadReferencesTo(id);
216    }
217
218    @Override
219    public boolean exists(NodeId id) throws ItemStateException
220    {
221        return _wrappedPM.exists(id);
222    }
223
224    @Override
225    public boolean exists(PropertyId id) throws ItemStateException
226    {
227        return _wrappedPM.exists(id);
228    }
229
230    @Override
231    public boolean existsReferencesTo(NodeId targetId) throws ItemStateException
232    {
233        return _wrappedPM.existsReferencesTo(targetId);
234    }
235
236    @Override
237    public void store(ChangeLog changeLog) throws ItemStateException
238    {
239        _wrappedPM.store(changeLog);
240    }
241    
242    @Override
243    public ConsistencyReport check(String[] uuids, boolean recursive, boolean fix, String lostNFoundId, ConsistencyCheckListener listener) throws RepositoryException
244    {
245        return _wrappedPM.check(uuids, recursive, fix, lostNFoundId, listener);
246    }
247
248    @Override
249    public void checkConsistency(String[] uuids, boolean recursive, boolean fix)
250    {
251        _wrappedPM.checkConsistency(uuids, recursive, fix);
252    }
253    
254    // BundleDBPersistenceManager methods
255    
256    @Override
257    public synchronized List<NodeId> getAllNodeIds(NodeId bigger, int maxCount) throws ItemStateException, RepositoryException
258    {
259        return _wrappedPM.getAllNodeIds(bigger, maxCount);
260    }
261    
262    @Override
263    public synchronized void destroy(NodeReferences refs) throws ItemStateException
264    {
265        _wrappedPM.destroy(refs);
266    }
267    
268    @Override
269    public synchronized Map<NodeId, NodeInfo> getAllNodeInfos(NodeId bigger, int maxCount) throws ItemStateException
270    {
271        return _wrappedPM.getAllNodeInfos(bigger, maxCount);
272    }
273    
274    @Override
275    public void setBlockOnConnectionLoss(String block)
276    {
277        _wrappedPM.setBlockOnConnectionLoss(block);
278    }
279    
280    @Override
281    public void setBundleCacheSize(String bundleCacheSize)
282    {
283        _wrappedPM.setBundleCacheSize(bundleCacheSize);
284    }
285    
286    @Override
287    public void setConnectionFactory(ConnectionFactory connectionFactory)
288    {
289        _wrappedPM.setConnectionFactory(connectionFactory);
290    }
291    
292    @Override
293    public void setConsistencyCheck(String check)
294    {
295        _wrappedPM.setConsistencyCheck(check);
296    }
297    
298    @Override
299    public void setConsistencyFix(String fix)
300    {
301        _wrappedPM.setConsistencyFix(fix);
302    }
303    
304    @Override
305    public void setErrorHandling(String errHandling)
306    {
307        _wrappedPM.setErrorHandling(errHandling);
308    }
309    
310    @Override
311    public void setEventChannel(UpdateEventChannel eventChannel)
312    {
313        _wrappedPM.setEventChannel(eventChannel);
314    }
315    
316    @Override
317    public void setExternalBLOBs(boolean externalBlobs)
318    {
319        _wrappedPM.setExternalBLOBs(externalBlobs);
320    }
321    
322    @Override
323    public void setMinBlobSize(String minBlobSize)
324    {
325        _wrappedPM.setMinBlobSize(minBlobSize);
326    }
327    
328    @Override
329    public void setSchemaObjectPrefix(String schemaPrefix)
330    {
331        _wrappedPM.setSchemaObjectPrefix(schemaPrefix);
332    }
333    
334    @Override
335    public String toString()
336    {
337        return _wrappedPM.toString();
338    }
339}