001/*
002 * Copyright (c) 2006-2013 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 */
013
014package org.nuxeo.runtime.datasource;
015
016import java.util.Enumeration;
017import java.util.HashMap;
018import java.util.Map;
019
020import javax.naming.Context;
021import javax.naming.NameClassPair;
022import javax.naming.NameNotFoundException;
023import javax.naming.NamingException;
024import javax.sql.DataSource;
025import javax.sql.XADataSource;
026
027import org.nuxeo.runtime.api.Framework;
028import org.nuxeo.runtime.jtajca.NuxeoContainer;
029
030/**
031 * Helper class to look up {@link DataSource}s without having to deal with vendor-specific JNDI prefixes.
032 *
033 * @author Thierry Delprat
034 * @author Florent Guillaume
035 */
036public class DataSourceHelper {
037
038    private DataSourceHelper() {
039    }
040
041    /**
042     * Get the JNDI prefix used for DataSource lookups.
043     */
044    public static String getDataSourceJNDIPrefix() {
045        return NuxeoContainer.nameOf("jdbc");
046    }
047
048    /**
049     * Look up a datasource JNDI name given a partial name.
050     * <p>
051     * For a datasource {@code "jdbc/foo"}, then it's sufficient to pass {@code "foo"} to this method.
052     *
053     * @param partialName the partial name
054     * @return the datasource JNDI name
055     */
056    public static String getDataSourceJNDIName(String name) {
057        return NuxeoContainer.nameOf(relativize(name));
058    }
059
060    protected static String relativize(String name) {
061        int idx = name.lastIndexOf("/");
062        if (idx > 0) {
063            name = name.substring(idx + 1);
064        }
065        return "jdbc/".concat(name);
066    }
067
068    /**
069     * Look up a datasource given a partial name.
070     * <p>
071     * For a datasource {@code "jdbc/foo"}, then it's sufficient to pass {@code "foo"} to this method.
072     *
073     * @param partialName the partial name
074     * @return the datasource
075     * @throws NamingException
076     */
077    public static DataSource getDataSource(String partialName) throws NamingException {
078        return getDataSource(partialName, DataSource.class);
079    }
080
081    public static XADataSource getXADataSource(String partialName) throws NamingException {
082        return getDataSource(partialName, XADataSource.class);
083    }
084
085    public static <T> T getDataSource(String name, Class<T> clazz) throws NamingException {
086        PooledDataSourceRegistry pools = Framework.getService(PooledDataSourceRegistry.class);
087        if (pools == null) {
088            throw new NamingException("runtime datasource no installed");
089        }
090        T ds = pools.getPool(relativize(name), clazz);
091        if (ds == null) {
092            throw new NameNotFoundException(name + " not found in container");
093        }
094        return ds;
095    }
096
097    public static Map<String, DataSource> getDatasources() throws NamingException {
098        String prefix = getDataSourceJNDIPrefix();
099        Context naming = NuxeoContainer.getRootContext();
100        if (naming == null) {
101            throw new NamingException("No root context");
102        }
103        Context jdbc = (Context) naming.lookup(prefix);
104        Enumeration<NameClassPair> namesPair = jdbc.list("");
105        Map<String, DataSource> datasourcesByName = new HashMap<String, DataSource>();
106        while (namesPair.hasMoreElements()) {
107            NameClassPair pair = namesPair.nextElement();
108            String name = pair.getName();
109            if (pair.isRelative()) {
110                name = prefix + "/" + name;
111            }
112            Object ds = naming.lookup(name);
113            if (ds instanceof DataSource) {
114                datasourcesByName.put(name, (DataSource) ds);
115            }
116        }
117        return datasourcesByName;
118    }
119
120    /**
121     * @param repositoryName
122     * @return
123     * @since TODO
124     */
125    public static String getDataSourceRepositoryJNDIName(String repositoryName) {
126        return getDataSourceJNDIName(ConnectionHelper.getPseudoDataSourceNameForRepository(repositoryName));
127    }
128}