001/*
002 * (C) Copyright 2006-2013 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 *     Nuxeo - initial API and implementation
018 *
019 */
020
021package org.nuxeo.runtime.datasource;
022
023import java.util.Enumeration;
024import java.util.HashMap;
025import java.util.Map;
026
027import javax.naming.Context;
028import javax.naming.NameClassPair;
029import javax.naming.NamingException;
030import javax.sql.DataSource;
031import javax.sql.XADataSource;
032
033import org.nuxeo.runtime.api.Framework;
034import org.nuxeo.runtime.jtajca.NuxeoContainer;
035
036/**
037 * Helper class to look up {@link DataSource}s without having to deal with vendor-specific JNDI prefixes.
038 *
039 * @author Thierry Delprat
040 * @author Florent Guillaume
041 */
042public class DataSourceHelper {
043
044    private DataSourceHelper() {
045    }
046
047    /**
048     * Get the JNDI prefix used for DataSource lookups.
049     */
050    public static String getDataSourceJNDIPrefix() {
051        return NuxeoContainer.nameOf("jdbc");
052    }
053
054    /**
055     * Look up a datasource JNDI name given a partial name.
056     * <p>
057     * For a datasource {@code "jdbc/foo"}, then it's sufficient to pass {@code "foo"} to this method.
058     *
059     * @param partialName the partial name
060     * @return the datasource JNDI name
061     */
062    public static String getDataSourceJNDIName(String name) {
063        return NuxeoContainer.nameOf(relativize(name));
064    }
065
066    protected static String relativize(String name) {
067        int idx = name.lastIndexOf("/");
068        if (idx > 0) {
069            name = name.substring(idx + 1);
070        }
071        return "jdbc/".concat(name);
072    }
073
074    /**
075     * Look up a datasource given a partial name.
076     * <p>
077     * For a datasource {@code "jdbc/foo"}, then it's sufficient to pass {@code "foo"} to this method.
078     *
079     * @param partialName the partial name
080     * @return the datasource
081     * @throws NamingException
082     */
083    public static DataSource getDataSource(String partialName) throws NamingException {
084        return getDataSource(partialName, DataSource.class);
085    }
086
087    public static XADataSource getXADataSource(String partialName) throws NamingException {
088        return getDataSource(partialName, XADataSource.class);
089    }
090
091    public static <T> T getDataSource(String name, Class<T> clazz) throws NamingException {
092        PooledDataSourceRegistry pools = Framework.getService(PooledDataSourceRegistry.class);
093        if (pools == null) {
094            throw new NamingException("runtime datasource no installed");
095        }
096        T ds = pools.getPool(relativize(name), clazz);
097        if (ds == null) {
098            return NuxeoContainer.lookup(name, clazz);
099        }
100        return ds;
101    }
102
103    public static Map<String, DataSource> getDatasources() throws NamingException {
104        String prefix = getDataSourceJNDIPrefix();
105        Context naming = NuxeoContainer.getRootContext();
106        if (naming == null) {
107            throw new NamingException("No root context");
108        }
109        Context jdbc = (Context) naming.lookup(prefix);
110        Enumeration<NameClassPair> namesPair = jdbc.list("");
111        Map<String, DataSource> datasourcesByName = new HashMap<>();
112        while (namesPair.hasMoreElements()) {
113            NameClassPair pair = namesPair.nextElement();
114            String name = pair.getName();
115            if (pair.isRelative()) {
116                name = prefix + "/" + name;
117            }
118            Object ds = naming.lookup(name);
119            if (ds instanceof DataSource) {
120                datasourcesByName.put(name, (DataSource) ds);
121            }
122        }
123        return datasourcesByName;
124    }
125
126}