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